From da604597acd40c1b2d29dc180ae742f6881488ac Mon Sep 17 00:00:00 2001 From: ygor-sena Date: Thu, 30 May 2024 23:17:22 -0300 Subject: [PATCH 1/2] fix(JOIN): fix uninitialized variable bug --- include/Channel.hpp | 9 ++++----- include/Client.hpp | 4 ++-- ircserv | Bin 227392 -> 0 bytes src/Channel.cpp | 20 ++++++++++++++------ src/Client.cpp | 11 ++++++----- src/Server.cpp | 4 ++-- tests/TestPrivmsg.cpp | 9 ++++----- 7 files changed, 32 insertions(+), 25 deletions(-) delete mode 100755 ircserv diff --git a/include/Channel.hpp b/include/Channel.hpp index 564871f..9a37eb0 100644 --- a/include/Channel.hpp +++ b/include/Channel.hpp @@ -6,7 +6,7 @@ /* By: yde-goes +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/21 08:24:04 by gilmar #+# #+# */ -/* Updated: 2024/05/30 15:35:19 by yde-goes ### ########.fr */ +/* Updated: 2024/05/30 22:54:51 by yde-goes ### ########.fr */ /* */ /* ************************************************************************** */ @@ -63,14 +63,13 @@ class Channel private: int _limit; + bool _has_key; + bool _invite_only; + bool _topic_restriction; std::string _key; std::string _name; - bool _invite_only; std::string _topic; - bool _topic_restriction; std::string _created_at; - - bool _has_key; std::vector_clients; // -> list of clients that are channel members std::vector_operator_clients; // -> list of channel operators }; diff --git a/include/Client.hpp b/include/Client.hpp index be06879..a9676c6 100644 --- a/include/Client.hpp +++ b/include/Client.hpp @@ -6,7 +6,7 @@ /* By: yde-goes +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/28 10:19:06 by gilmar #+# #+# */ -/* Updated: 2024/05/30 13:11:52 by yde-goes ### ########.fr */ +/* Updated: 2024/05/30 22:45:05 by yde-goes ### ########.fr */ /* */ /* ************************************************************************** */ @@ -70,9 +70,9 @@ class Client //-> class for client private: int _fd; //-> client file descriptor bool _is_logged; //-> boolean for login - std::string _buffer; //-> client buffer bool _is_authenticated; //-> boolean for authentication bool _is_operator; //-> boolean for channel operator + std::string _buffer; //-> client buffer std::string _ip_addr; //-> client ip address std::string _nickname; //-> client nickname std::string _username; //-> client username diff --git a/ircserv b/ircserv deleted file mode 100755 index 78ced6d2d8deca624d50993fb79aafa7d32cd0a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 227392 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

+d4|ZjI;v(BHZI%^au)^fz{f&?NjGgWnu^ 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

4a_(e@wa=^E#fMXxN8v?8jNcZlt0ZN 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 diff --git a/src/Channel.cpp b/src/Channel.cpp index b5fdb92..9e5a185 100644 --- a/src/Channel.cpp +++ b/src/Channel.cpp @@ -6,7 +6,7 @@ /* By: yde-goes +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/21 08:26:17 by gilmar #+# #+# */ -/* Updated: 2024/05/30 15:36:08 by yde-goes ### ########.fr */ +/* Updated: 2024/05/30 22:51:03 by yde-goes ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,22 +18,30 @@ Channel::Channel() { + _limit = -1; + _has_key = false; + _invite_only = false; + _topic_restriction = false; _key = ""; _name = ""; _topic = ""; - _limit = -1; _created_at = ""; - _has_key = false; + _clients = std::vector(); + _operator_clients = std::vector(); } Channel::Channel(std::string name) { - _key = ""; - _topic = ""; _limit = -1; + _has_key = false; + _invite_only = false; + _topic_restriction = false; + _key = ""; _name = name; + _topic = ""; _created_at = ""; - _has_key = false; + _clients = std::vector(); + _operator_clients = std::vector(); } /* diff --git a/src/Client.cpp b/src/Client.cpp index 8826c50..ffbf5d9 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -6,7 +6,7 @@ /* By: yde-goes +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/28 10:20:02 by gilmar #+# #+# */ -/* Updated: 2024/05/30 13:11:43 by yde-goes ### ########.fr */ +/* Updated: 2024/05/30 22:48:46 by yde-goes ### ########.fr */ /* */ /* ************************************************************************** */ @@ -19,14 +19,15 @@ Client::Client() { _fd = -1; + _is_logged = false; + _is_authenticated = false; + _is_operator = false; + _buffer = ""; _ip_addr = ""; _nickname = ""; _username = ""; _password = ""; - _buffer = ""; - _is_logged = false; - _is_authenticated = false; - _is_operator = false; + _channels_invited = std::vector(); } /* diff --git a/src/Server.cpp b/src/Server.cpp index db227a2..a8c2479 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: gilmar +#+ +:+ +#+ */ +/* By: yde-goes +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/28 10:26:55 by gilmar #+# #+# */ -/* Updated: 2024/05/30 15:59:59 by gilmar ### ########.fr */ +/* Updated: 2024/05/30 22:36:33 by yde-goes ### ########.fr */ /* */ /* ************************************************************************** */ diff --git a/tests/TestPrivmsg.cpp b/tests/TestPrivmsg.cpp index ca4ed9e..a0f6144 100644 --- a/tests/TestPrivmsg.cpp +++ b/tests/TestPrivmsg.cpp @@ -6,7 +6,7 @@ /* By: yde-goes +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/05/25 09:03:10 by yde-goes #+# #+# */ -/* Updated: 2024/05/25 21:15:42 by yde-goes ### ########.fr */ +/* Updated: 2024/05/30 23:00:22 by yde-goes ### ########.fr */ /* */ /* ************************************************************************** */ @@ -57,7 +57,7 @@ Client *senderClient() return client; } -/* Test(PrivmsgCommand, privmsg_successfully_single_client) +Test(PrivmsgCommand, privmsg_successfully_single_client) { Client *sender = senderClient(); Client *first = firstReceiver(); @@ -108,7 +108,7 @@ Test(PrivmsgCommand, privmsg_successfully_single_channel) server._handler_client_privmsg("#brazil :Hello, BRAZIL!", 4); cr_assert(eq(int, server._reply_code, 0)); -} */ +} Test(PrivmsgCommand, privmsg_successfully_three_channels) { @@ -140,7 +140,7 @@ Test(PrivmsgCommand, privmsg_successfully_three_channels) cr_assert(eq(int, server._reply_code, 0)); } -/* Test(PrivmsgCommand, privmsg_successfully_mixed_channel_user) +Test(PrivmsgCommand, privmsg_successfully_mixed_channel_user) { Client *sender = senderClient(); Client *first = firstReceiver(); @@ -264,4 +264,3 @@ Test(PrivmsgCommand, err_nosuchnick) server._handler_client_privmsg("#brazil,thirdUser,#france,secondUser,#spain :Hello, WORLD!", 4); cr_assert(eq(int, server._reply_code, 401)); } - */ \ No newline at end of file From dfad667eb8ecc12043ea904ee661c3c17d76b2dc Mon Sep 17 00:00:00 2001 From: ygor-sena Date: Thu, 30 May 2024 23:51:00 -0300 Subject: [PATCH 2/2] chore(style): add code style automation with .clang-format --- .clang-format | 31 +++ include/Channel.hpp | 107 +++++----- include/Client.hpp | 114 +++++------ include/MarvinBot.hpp | 85 ++++---- include/Replies.hpp | 167 ++++++++++------ include/Server.hpp | 248 ++++++++++++----------- src/Channel.cpp | 256 ++++++++++++------------ src/Client.cpp | 146 +++++--------- src/MarvinBot.cpp | 135 +++++++------ src/Server.cpp | 390 ++++++++++++++++++++++--------------- src/commands/Invite.cpp | 149 +++++++------- src/commands/Join.cpp | 144 +++++++------- src/commands/Kick.cpp | 149 ++++++++------ src/commands/Mode.cpp | 313 ++++++++++++++++------------- src/commands/Nick.cpp | 40 ++-- src/commands/Part.cpp | 94 +++++---- src/commands/Pass.cpp | 36 ++-- src/commands/Privmsg.cpp | 101 ++++++---- src/commands/Quit.cpp | 42 ++-- src/commands/Topic.cpp | 67 ++++--- src/commands/User.cpp | 73 ++++--- src/main.cpp | 5 +- tests/TestInvite.cpp | 63 +++--- tests/TestJoin.cpp | 20 +- tests/TestKick.cpp | 59 +++--- tests/TestMarvinBot.cpp | 10 +- tests/TestMode.cpp | 1 - tests/TestNick.cpp | 44 ++--- tests/TestPart.cpp | 38 ++-- tests/TestPass.cpp | 102 +++++----- tests/TestPrivmsg.cpp | 124 ++++++------ tests/TestQuit.cpp | 54 +++-- tests/TestSplitMessage.cpp | 80 +++++--- tests/TestTopic.cpp | 39 ++-- tests/TestUser.cpp | 30 +-- tests/Utils.cpp | 11 +- tests/Utils.hpp | 10 +- 37 files changed, 1982 insertions(+), 1595 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..208cfa3 --- /dev/null +++ b/.clang-format @@ -0,0 +1,31 @@ +--- +Language: Cpp +BasedOnStyle: Google +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: false +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: true +BreakBeforeBraces: Allman +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 80 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +DerivePointerAlignment: false +IncludeBlocks: Preserve +IndentCaseLabels: false +IndentPPDirectives: None +UseTab: Always +IndentWidth: 4 +TabWidth: 4 diff --git a/include/Channel.hpp b/include/Channel.hpp index 9a37eb0..746ee79 100644 --- a/include/Channel.hpp +++ b/include/Channel.hpp @@ -11,67 +11,68 @@ /* ************************************************************************** */ #ifndef CHANNEL_HPP -# define CHANNEL_HPP +#define CHANNEL_HPP -# include "Client.hpp" -# include "Replies.hpp" +#include "Client.hpp" +#include "Replies.hpp" class Channel { - public: - Channel(); - ~Channel(); - Channel(std::string name); + public: + Channel(); + ~Channel(); + Channel(std::string name); - int get_clients_size(void) const; - std::string get_name(void) const; - std::string get_topic(void) const; - std::string get_channel_key(void) const; - std::string get_client_names(void) const; - std::vector get_channel_clients(void); - std::vector get_operator_clients(void); - bool get_topic_restriction(void) const; + int get_clients_size(void) const; + std::string get_name(void) const; + std::string get_topic(void) const; + std::string get_channel_key(void) const; + std::string get_client_names(void) const; + std::vector get_channel_clients(void); + std::vector get_operator_clients(void); + bool get_topic_restriction(void) const; - void set_limit(int limit); - void set_invite_only(void); - void set_topic_restriction(void); - void set_topic(std::string topic); - void set_key(std::string password); - void set_channel_operator(Client *client); + void set_limit(int limit); + void set_invite_only(void); + void set_topic_restriction(void); + void set_topic(std::string topic); + void set_key(std::string password); + void set_channel_operator(Client* client); - void remove_key(void); - void remove_limit(void); - void remove_invite_only(void); - void remove_topic_restriction(void); - void remove_channel_operator(Client *client); - void remove_channel_client(Client *client); - - void join(Client *client); - void kick(Client *client); - void part(Client *client); - void invite(Client *client); - void broadcast(Client *sender, std::string target, std::string message); - - bool has_key(void) const; - bool has_client(Client *client); + void remove_key(void); + void remove_limit(void); + void remove_invite_only(void); + void remove_topic_restriction(void); + void remove_channel_operator(Client* client); + void remove_channel_client(Client* client); - bool is_channel_full(void) const; - bool is_channel_operator(const int fd); - bool is_channel_invite_only(void) const; - bool is_channel_operator(std::string nickname); - bool is_client_in_channel(std::string nickname); + void join(Client* client); + void kick(Client* client); + void part(Client* client); + void invite(Client* client); + void broadcast(Client* sender, std::string target, std::string message); - private: - int _limit; - bool _has_key; - bool _invite_only; - bool _topic_restriction; - std::string _key; - std::string _name; - std::string _topic; - std::string _created_at; - std::vector_clients; // -> list of clients that are channel members - std::vector_operator_clients; // -> list of channel operators + bool has_key(void) const; + bool has_client(Client* client); + + bool is_channel_full(void) const; + bool is_channel_operator(const int fd); + bool is_channel_invite_only(void) const; + bool is_channel_operator(std::string nickname); + bool is_client_in_channel(std::string nickname); + + private: + int _limit; + bool _has_key; + bool _invite_only; + bool _topic_restriction; + std::string _key; + std::string _name; + std::string _topic; + std::string _created_at; + std::vector + _clients; // -> list of clients that are channel members + std::vector _operator_clients; // -> list of channel operators }; -#endif //CHANNEL_HPP \ No newline at end of file +#endif // CHANNEL_HPP \ No newline at end of file diff --git a/include/Client.hpp b/include/Client.hpp index a9676c6..8f1254f 100644 --- a/include/Client.hpp +++ b/include/Client.hpp @@ -11,73 +11,73 @@ /* ************************************************************************** */ #ifndef CLIENT_HPP -# define CLIENT_HPP +#define CLIENT_HPP -# include -# include //-> for vector -# include //-> for socket() -# include //-> for socket() -# include //-> for sockaddr_in -# include //-> for fcntl() -# include //-> for close() -# include //-> for inet_ntoa() -# include //-> for poll() -# include //-> for signal() -# include -# include -# include "Replies.hpp" +#include //-> for inet_ntoa() +#include //-> for fcntl() +#include //-> for sockaddr_in +#include //-> for poll() +#include //-> for socket() +#include //-> for socket() +#include //-> for close() +#include +#include //-> for signal() +#include +#include +#include //-> for vector +#include "Replies.hpp" //-------------------------------------------------------// -# define RED "\e[1;31m" //-> for red color -# define WHI "\e[0;37m" //-> for white color -# define GRE "\e[1;32m" //-> for green color -# define YEL "\e[1;33m" //-> for yellow color +#define RED "\e[1;31m" //-> for red color +#define WHI "\e[0;37m" //-> for white color +#define GRE "\e[1;32m" //-> for green color +#define YEL "\e[1;33m" //-> for yellow color //-------------------------------------------------------// -class Client //-> class for client +class Client //-> class for client { - public: - Client(); + public: + Client(); - int get_fd() const; - bool get_is_logged() const; - std::string get_buffer() const; - std::string get_nickname() const; - std::string get_username() const; - std::string get_password() const; - std::string get_hostname() const; - std::vector get_channels_invited() const; - std::string get_ip_address() const; - bool get_is_authenticated() const; - bool get_is_operator() const; + int get_fd() const; + bool get_is_logged() const; + std::string get_buffer() const; + std::string get_nickname() const; + std::string get_username() const; + std::string get_password() const; + std::string get_hostname() const; + std::vector get_channels_invited() const; + std::string get_ip_address() const; + bool get_is_authenticated() const; + bool get_is_operator() const; - void set_fd(const int fd); - void set_is_logged(bool is_logged); - void set_ip_add(const std::string &ipadd); - void set_buffer(const std::string &buffer); - void set_nickname(const std::string &nickname); - void set_username(const std::string &username); - void set_password(const std::string &password); - void set_is_authenticated(bool is_authenticated); - void set_is_operator(bool is_operator); + void set_fd(const int fd); + void set_is_logged(bool is_logged); + void set_ip_add(const std::string& ipadd); + void set_buffer(const std::string& buffer); + void set_nickname(const std::string& nickname); + void set_username(const std::string& username); + void set_password(const std::string& password); + void set_is_authenticated(bool is_authenticated); + void set_is_operator(bool is_operator); - bool is_channel_invited(const std::string &channel); - void add_channel_invited(const std::string &channel); - void remove_channel_invited(const std::string &channel); + bool is_channel_invited(const std::string& channel); + void add_channel_invited(const std::string& channel); + void remove_channel_invited(const std::string& channel); - void broadcast(Client *sender, std::string target, std::string message); + void broadcast(Client* sender, std::string target, std::string message); - private: - int _fd; //-> client file descriptor - bool _is_logged; //-> boolean for login - bool _is_authenticated; //-> boolean for authentication - bool _is_operator; //-> boolean for channel operator - std::string _buffer; //-> client buffer - std::string _ip_addr; //-> client ip address - std::string _nickname; //-> client nickname - std::string _username; //-> client username - std::string _password; //-> client password - std::vector _channels_invited; //-> vector of channels invited + private: + int _fd; //-> client file descriptor + bool _is_logged; //-> boolean for login + bool _is_authenticated; //-> boolean for authentication + bool _is_operator; //-> boolean for channel operator + std::string _buffer; //-> client buffer + std::string _ip_addr; //-> client ip address + std::string _nickname; //-> client nickname + std::string _username; //-> client username + std::string _password; //-> client password + std::vector _channels_invited; //-> vector of channels invited }; -#endif // CLIENT_HPP \ No newline at end of file +#endif // CLIENT_HPP \ No newline at end of file diff --git a/include/MarvinBot.hpp b/include/MarvinBot.hpp index 12ac3f1..03c1c39 100644 --- a/include/MarvinBot.hpp +++ b/include/MarvinBot.hpp @@ -11,47 +11,54 @@ /* ************************************************************************** */ #ifndef MARVINBOT_HPP -# define MARVINBOT_HPP - -# include "Server.hpp" -# include "Replies.hpp" - -# define SOCRATES_KNOWLEDGE "I know that I know nothing. - Socrates" -# define DESCARTES_EXISTENCE "I think, therefore I am. - René Descartes" -# define KANT_CATEGORICAL_IMPERATIVE "Act only according to that maxim whereby you can, at the same time, will that it should become a universal law. - Immanuel Kant" -# define NIETZSCHE_GOD "God is dead! - Friedrich Nietzsche" -# define PLATO_FORMS "The Forms are eternal and changeless. - Plato" -# define MARX_RELIGION "Religion is the opium of the people. - Karl Marx" -# define CONFUCIUS_WISDOM "Real knowledge is to know the extent of one's ignorance. - Confucius" -# define HUME_SCIENCE "A wise man proportions his belief to the evidence. - David Hume" -# define HEIDEGGER_BEING "Being is time, and time is finite. - Martin Heidegger" -# define ROUSSEAU_FREEDOM "Man is born free, and everywhere he is in chains. - Jean-Jacques Rousseau" +#define MARVINBOT_HPP + +#include "Replies.hpp" +#include "Server.hpp" + +#define SOCRATES_KNOWLEDGE "I know that I know nothing. - Socrates" +#define DESCARTES_EXISTENCE "I think, therefore I am. - René Descartes" +#define KANT_CATEGORICAL_IMPERATIVE \ + "Act only according to that maxim whereby you can, at the same time, " \ + "will that it should become a universal law. - Immanuel Kant" +#define NIETZSCHE_GOD "God is dead! - Friedrich Nietzsche" +#define PLATO_FORMS "The Forms are eternal and changeless. - Plato" +#define MARX_RELIGION "Religion is the opium of the people. - Karl Marx" +#define CONFUCIUS_WISDOM \ + "Real knowledge is to know the extent of one's ignorance. - Confucius" +#define HUME_SCIENCE \ + "A wise man proportions his belief to the evidence. - David Hume" +#define HEIDEGGER_BEING "Being is time, and time is finite. - Martin Heidegger" +#define ROUSSEAU_FREEDOM \ + "Man is born free, and everywhere he is in chains. - Jean-Jacques " \ + "Rousseau" class MarvinBot { - public: - MarvinBot(); - ~MarvinBot(); - - // Enum for quotes - enum EnumMarvinBotQuotes { - QUOTE_SOCRATES_KNOWLEDGE, - QUOTE_DESCARTES_EXISTENCE, - QUOTE_KANT_CATEGORICAL_IMPERATIVE, - QUOTE_NIETZSCHE_GOD, - QUOTE_PLATO_FORMS, - QUOTE_MARX_RELIGION, - QUOTE_CONFUCIUS_WISDOM, - QUOTE_HUME_SCIENCE, - QUOTE_HEIDEGGER_BEING, - QUOTE_ROUSSEAU_FREEDOM, - QUOTES_COUNT // To keep track of the number of quotes - }; - - const char* marvin_bot_quotes[QUOTES_COUNT]; - - private: - std::string _return_quote(); + public: + MarvinBot(); + ~MarvinBot(); + + // Enum for quotes + enum EnumMarvinBotQuotes + { + QUOTE_SOCRATES_KNOWLEDGE, + QUOTE_DESCARTES_EXISTENCE, + QUOTE_KANT_CATEGORICAL_IMPERATIVE, + QUOTE_NIETZSCHE_GOD, + QUOTE_PLATO_FORMS, + QUOTE_MARX_RELIGION, + QUOTE_CONFUCIUS_WISDOM, + QUOTE_HUME_SCIENCE, + QUOTE_HEIDEGGER_BEING, + QUOTE_ROUSSEAU_FREEDOM, + QUOTES_COUNT // To keep track of the number of quotes + }; + + const char* marvin_bot_quotes[QUOTES_COUNT]; + + private: + std::string _return_quote(); }; -#endif // MARVINBOT_HPP \ No newline at end of file +#endif // MARVINBOT_HPP \ No newline at end of file diff --git a/include/Replies.hpp b/include/Replies.hpp index bf0882c..e2a1d3e 100644 --- a/include/Replies.hpp +++ b/include/Replies.hpp @@ -11,74 +11,131 @@ /* ************************************************************************** */ #ifndef REPLIES_HPP -# define REPLIES_HPP +#define REPLIES_HPP -# define CRLF "\r\n" +#define CRLF "\r\n" // refer to https://datatracker.ietf.org/doc/html/rfc1459 -# define RPL_CONNECTED(nickname) (": 001 " + nickname + " : Welcome to the IRC server!" + CRLF) +#define RPL_CONNECTED(nickname) \ + (": 001 " + nickname + " : Welcome to the IRC server!" + CRLF) -# define RPL_UMODEIS(hostname, channelname, mode, user) ":" + hostname + " MODE " + channelname + " " + mode + " " + user + CRLF +#define RPL_UMODEIS(hostname, channelname, mode, user) \ + ":" + hostname + " MODE " + channelname + " " + mode + " " + user + CRLF -# define RPL_CREATIONTIME(nickname, channelname, creationtime) ": 329 " + nickname + " " + channelname + " " + creationtime + CRLF +#define RPL_CREATIONTIME(nickname, channelname, creationtime) \ + ": 329 " + nickname + " " + channelname + " " + creationtime + CRLF -# define RPL_CHANNELMODES(nickname, channelname, modes) ": 324 " + nickname + " " + channelname + " " + modes + CRLF +#define RPL_CHANNELMODES(nickname, channelname, modes) \ + ": 324 " + nickname + " " + channelname + " " + modes + CRLF -# define RPL_CHANGEMODE(hostname, channelname, mode, arguments) (":" + hostname + " MODE " + channelname + " " + mode + " " + arguments + CRLF) +#define RPL_CHANGEMODE(hostname, channelname, mode, arguments) \ + (":" + hostname + " MODE " + channelname + " " + mode + " " + arguments + \ + CRLF) -# define RPL_NICKCHANGE(oldnickname, nickname) (":" + oldnickname + " NICK " + nickname + CRLF) +#define RPL_NICKCHANGE(oldnickname, nickname) \ + (":" + oldnickname + " NICK " + nickname + CRLF) -# define RPL_JOINMSG(hostname, ipaddress, channelname) (":" + hostname + "@" + ipaddress + " JOIN " + channelname + CRLF) +#define RPL_JOINMSG(hostname, ipaddress, channelname) \ + (":" + hostname + "@" + ipaddress + " JOIN " + channelname + CRLF) -# define RPL_NAMREPLY(nickname, channelname, clientslist) (": 353 " + nickname + " @ " + channelname + " :" + clientslist + CRLF) +#define RPL_NAMREPLY(nickname, channelname, clientslist) \ + (": 353 " + nickname + " @ " + channelname + " :" + clientslist + CRLF) -# define RPL_ENDOFNAMES(nickname, channelname) (": 366 " + nickname + " " + channelname + " :END of /NAMES list" + CRLF) +#define RPL_ENDOFNAMES(nickname, channelname) \ + (": 366 " + nickname + " " + channelname + " :END of /NAMES list" + CRLF) // Topic -# define RPL_TOPIC(nickname, channelname, topic) (": 332 " + nickname + " " +channelname + " :" + topic + CRLF) -# define RPL_NOTOPIC(nickname, channelname) (": 331 " + nickname + " " +channelname + " : No topic is set " + CRLF) - -# define RPL_QUITMESSAGE(nickname) (": 301 " + nickname + " :You have quit the server." + CRLF) -# define RPL_PART(hostname, channelname, nickname) (":" + hostname + " PART " + channelname + " :" + nickname + " has left the channel" + CRLF) -# define RPL_KICK(hostname, channelname, kickername, kickedname, comment) (":" + hostname + " KICK " + channelname + " " + kickedname + " :" + kickername + " " + comment + CRLF) -# define RPL_INVITING(hostname, channelname, invitername, invitedname) (":" + hostname + " INVITE " + invitedname + " " + channelname + CRLF) -# define RPL_PRIVMSG(hostname, receiver, text) (":" + hostname + " PRIVMSG " + receiver + " " + text + CRLF) - -# define BOT_CMDMARVIN(nickname) (": 4242 marvin_bot " + nickname + " :Hello, I am Marvin, the paranoid robot." + CRLF) -# define BOT_CMDTIME(nickname, time) (": 4242 marvin_bot " + nickname + " :Server time: " + time_str) -# define BOT_CMDWHOIS(nickname, username, ipaddr) (": 4242 marvin_bot " + nickname + " :Whois " + username + " " + ipaddr + " :End of WHOIS list" + CRLF) -# define BOT_CMDQUOTE(nickname, quote) (": 4242 marvin_bot " + nickname + " :" + quote + CRLF) -# define BOT_CLIENTNOTINCHANNEL(nickname) (": 2424 marvin_bot " + nickname + ": Must be part of at least one channel to use marvin commands" + CRLF) -# define BOT_WHOISDOESNTEXIST(nickname) (": 4242 marvin_bot " + nickname + " :No such user" + CRLF) +#define RPL_TOPIC(nickname, channelname, topic) \ + (": 332 " + nickname + " " + channelname + " :" + topic + CRLF) +#define RPL_NOTOPIC(nickname, channelname) \ + (": 331 " + nickname + " " + channelname + " : No topic is set " + CRLF) + +#define RPL_QUITMESSAGE(nickname) \ + (": 301 " + nickname + " :You have quit the server." + CRLF) +#define RPL_PART(hostname, channelname, nickname) \ + (":" + hostname + " PART " + channelname + " :" + nickname + \ + " has left the channel" + CRLF) +#define RPL_KICK(hostname, channelname, kickername, kickedname, comment) \ + (":" + hostname + " KICK " + channelname + " " + kickedname + " :" + \ + kickername + " " + comment + CRLF) +#define RPL_INVITING(hostname, channelname, invitername, invitedname) \ + (":" + hostname + " INVITE " + invitedname + " " + channelname + CRLF) +#define RPL_PRIVMSG(hostname, receiver, text) \ + (":" + hostname + " PRIVMSG " + receiver + " " + text + CRLF) + +#define BOT_CMDMARVIN(nickname) \ + (": 4242 marvin_bot " + nickname + \ + " :Hello, I am Marvin, the paranoid robot." + CRLF) +#define BOT_CMDTIME(nickname, time) \ + (": 4242 marvin_bot " + nickname + " :Server time: " + time_str) +#define BOT_CMDWHOIS(nickname, username, ipaddr) \ + (": 4242 marvin_bot " + nickname + " :Whois " + username + " " + ipaddr + \ + " :End of WHOIS list" + CRLF) +#define BOT_CMDQUOTE(nickname, quote) \ + (": 4242 marvin_bot " + nickname + " :" + quote + CRLF) +#define BOT_CLIENTNOTINCHANNEL(nickname) \ + (": 2424 marvin_bot " + nickname + \ + ": Must be part of at least one channel to use marvin commands" + CRLF) +#define BOT_WHOISDOESNTEXIST(nickname) \ + (": 4242 marvin_bot " + nickname + " :No such user" + CRLF) ///////// ERRORS ///////// -# define ERR_NEEDMODEPARM(channelname, mode) (": 696 " + channelname + " * You must specify a parameter for the key mode. " + mode + CRLF) -# define ERR_INVALIDMODEPARM(channelname, mode) (": 696 " + channelname + " Invalid mode parameter. " + mode + CRLF) -# define ERR_KEYSET(channelname) ": 467 " + channelname + " Channel key already set. " + CRLF -# define ERR_UNKNOWNMODE(nickname, channelname, mode) ": 472 " + nickname + " " + channelname + " " + mode + " :is not a recognised channel mode" + CRLF -# define ERR_NEEDMOREPARAMS(nickname) (": 461 " + nickname + " :Not enough parameters." + CRLF) -# define ERR_CHANNELNOTFOUND(nickname, channelname) (": 403 " + nickname + " " + channelname + " :No such channel" + CRLF) -# define ERR_NOTOPERATOR(channelname) (": 482 " + channelname + " :You're not a channel operator" + CRLF) -# define ERR_NOSUCHNICK(channelname, name) (": 401 " + channelname + " " + name + " :No such nick/channel" + CRLF) -# define ERR_INCORPASS(nickname) (": 464 " + nickname + " :Password incorrect !" + CRLF ) -# define ERR_NONICKNAME(nickname) (": 431 " + nickname + " :No nickname given" + CRLF ) -# define ERR_NICKINUSE(nickname) (": 433 " + nickname + " :Nickname is already in use" + CRLF) - - -# define ERR_ALREADYREGISTERED(nickname) (": 462 " + nickname + " :You may not reregister !" + CRLF ) -# define ERR_NOTREGISTERED(nickname) (": 451 " + nickname + " :You have not registered!" + CRLF) - -# define ERR_CMDNOTFOUND(nickname, command) (": 421 " + nickname + " " + command + " :Unknown command" + CRLF) - -# define ERR_BADCHANNELKEY(nickname, channelname) (": 475 " + nickname + " " + channelname + " :Cannot join channel (incorrect key)" + CRLF) -# define ERR_INVITEONLYCHAN(nickname, channelname) (": 473 " + nickname + " " + channelname + " :Cannot join channel (+i)" + CRLF) -# define ERR_CHANNELISFULL(nickname, channelname) (": 422 " + nickname + " " + channelname + " :Cannot join channel (+l)" + CRLF) -# define ERR_NOSUCHCHANNEL(channelname) (": 403 " + channelname + " :No such channel" + CRLF) -# define ERR_USERNOTINCHANNEL(nickname, channelname) ("441 " + nickname + " " + channelname + " :They aren't on that channel" + CRLF) -# define ERR_NOTONCHANNEL(channelname) (": 442 " + channelname + " :You're not on that channel" + CRLF) -# define ERR_USERONCHANNEL(user, channelname) (": 443 " + user + " " + channelname + " :is already on channel" + CRLF) -# define ERR_CHANOPRIVSNEEDED(channelname) (": 482 " + channelname + " :You're not a channel operator" + CRLF) -# define ERR_NOPRIVILEGES(nickname) (": 481 " + nickname + " :Permission Denied- You're not an IRC operator" + CRLF) - -#endif // REPLIES_HPP +#define ERR_NEEDMODEPARM(channelname, mode) \ + (": 696 " + channelname + \ + " * You must specify a parameter for the key mode. " + mode + CRLF) +#define ERR_INVALIDMODEPARM(channelname, mode) \ + (": 696 " + channelname + " Invalid mode parameter. " + mode + CRLF) +#define ERR_KEYSET(channelname) \ + ": 467 " + channelname + " Channel key already set. " + CRLF +#define ERR_UNKNOWNMODE(nickname, channelname, mode) \ + ": 472 " + nickname + " " + channelname + " " + mode + \ + " :is not a recognised channel mode" + CRLF +#define ERR_NEEDMOREPARAMS(nickname) \ + (": 461 " + nickname + " :Not enough parameters." + CRLF) +#define ERR_CHANNELNOTFOUND(nickname, channelname) \ + (": 403 " + nickname + " " + channelname + " :No such channel" + CRLF) +#define ERR_NOTOPERATOR(channelname) \ + (": 482 " + channelname + " :You're not a channel operator" + CRLF) +#define ERR_NOSUCHNICK(channelname, name) \ + (": 401 " + channelname + " " + name + " :No such nick/channel" + CRLF) +#define ERR_INCORPASS(nickname) \ + (": 464 " + nickname + " :Password incorrect !" + CRLF) +#define ERR_NONICKNAME(nickname) \ + (": 431 " + nickname + " :No nickname given" + CRLF) +#define ERR_NICKINUSE(nickname) \ + (": 433 " + nickname + " :Nickname is already in use" + CRLF) + +#define ERR_ALREADYREGISTERED(nickname) \ + (": 462 " + nickname + " :You may not reregister !" + CRLF) +#define ERR_NOTREGISTERED(nickname) \ + (": 451 " + nickname + " :You have not registered!" + CRLF) + +#define ERR_CMDNOTFOUND(nickname, command) \ + (": 421 " + nickname + " " + command + " :Unknown command" + CRLF) + +#define ERR_BADCHANNELKEY(nickname, channelname) \ + (": 475 " + nickname + " " + channelname + \ + " :Cannot join channel (incorrect key)" + CRLF) +#define ERR_INVITEONLYCHAN(nickname, channelname) \ + (": 473 " + nickname + " " + channelname + " :Cannot join channel (+i)" + \ + CRLF) +#define ERR_CHANNELISFULL(nickname, channelname) \ + (": 422 " + nickname + " " + channelname + " :Cannot join channel (+l)" + \ + CRLF) +#define ERR_NOSUCHCHANNEL(channelname) \ + (": 403 " + channelname + " :No such channel" + CRLF) +#define ERR_USERNOTINCHANNEL(nickname, channelname) \ + ("441 " + nickname + " " + channelname + " :They aren't on that channel" + \ + CRLF) +#define ERR_NOTONCHANNEL(channelname) \ + (": 442 " + channelname + " :You're not on that channel" + CRLF) +#define ERR_USERONCHANNEL(user, channelname) \ + (": 443 " + user + " " + channelname + " :is already on channel" + CRLF) +#define ERR_CHANOPRIVSNEEDED(channelname) \ + (": 482 " + channelname + " :You're not a channel operator" + CRLF) +#define ERR_NOPRIVILEGES(nickname) \ + (": 481 " + nickname + " :Permission Denied- You're not an IRC operator" + \ + CRLF) + +#endif // REPLIES_HPP diff --git a/include/Server.hpp b/include/Server.hpp index 2b5de62..dd1efbc 100644 --- a/include/Server.hpp +++ b/include/Server.hpp @@ -6,132 +6,150 @@ /* By: yde-goes +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/28 10:23:47 by gilmar #+# #+# */ -/* Updated: 2024/05/29 19:17:18 by yde-goes ### ########.fr */ +/* Updated: 2024/05/30 23:45:41 by yde-goes ### ########.fr */ /* */ /* ************************************************************************** */ #ifndef SERVER_HPP -# define SERVER_HPP - -# include // Para std::to_string -# include -# include // para a função std::atoi -# include -# include //-> for vector -# include //-> for socket() -# include //-> for socket() -# include //-> for sockaddr_in -# include //-> for fcntl() -# include //-> for close() -# include //-> for inet_ntoa() -# include //-> for poll() -# include //-> for signal() -# include //-> for std::stringstream -# include -# include //-> for map +#define SERVER_HPP + +#include //-> for inet_ntoa() +#include //-> for fcntl() +#include //-> for sockaddr_in +#include //-> for poll() +#include //-> for socket() +#include //-> for socket() +#include //-> for close() +#include //-> for signal() +#include // para a função std::atoi +#include +#include +#include +#include //-> for map +#include //-> for std::stringstream +#include // Para std::to_string +#include //-> for vector //-------------------------------------------------------// -# define RED "\e[1;31m" //-> for red color -# define WHI "\e[0;37m" //-> for white color -# define GRE "\e[1;32m" //-> for green color -# define YEL "\e[1;33m" //-> for yellow color +#define RED "\e[1;31m" //-> for red color +#define WHI "\e[0;37m" //-> for white color +#define GRE "\e[1;32m" //-> for green color +#define YEL "\e[1;33m" //-> for yellow color //-------------------------------------------------------// -# include "Client.hpp" //-> for client class -# include "Replies.hpp" //-> for replies class -# include "Channel.hpp" //-> for channel class +#include "Channel.hpp" //-> for channel class +#include "Client.hpp" //-> for client class +#include "Replies.hpp" //-> for replies class -# define SPACE " " -# define CRLF "\r\n" -# define LINE_FEED "\n" -# define DELIMITER " \t" +#define SPACE " " +#define CRLF "\r\n" +#define LINE_FEED "\n" +#define DELIMITER " \t" class Server { - public: - Server(); - ~Server(); - // This contructor is to be used as a workaround for mockup tests - Server(std::string password, std::vector _clients, std::vector _channels); - - void init(const std::string &port, const std::string &password); - - private: - int _port; //-> server port - int _server_fdsocket; //-> server socket file descriptor - std::string _password; //-> server password - std::vector _clients; //-> vector of clients - std::vector _fds; //-> vector of pollfd - struct sockaddr_in _server_addr; //-> server address - std::vector _channels; //-> vector of channels - - int _reply_code; // -> This a workaround to test the IRC commands without mocking up a client-server connection - - int get_reply_code(void); // -> Get the reply code to be checked against criterion test results - void _is_valid_port(const std::string &port); - bool _is_valid_nickname(const std::string &nickname); - bool _is_nickname_in_use(const int fd, const std::string &nickname); - bool _is_client_in_any_channel(const int fd); - - void _handler_client_join(const std::string &buffer, const int fd); - void _handler_client_quit(const std::string &buffer, const int fd); - void _handler_client_part(const std::string &buffer, const int fd); - void _handler_client_mode(const std::string &buffer, const int fd); - void _handler_client_kick(const std::string &buffer, const int fd); - void _handler_client_topic(const std::string &buffer, const int fd); - void _handler_client_invite(const std::string &buffer, const int fd); - void _handler_client_privmsg(const std::string &buffer, const int fd); - void _handler_client_nickname(const std::string &nickname, const int fd); - void _handler_client_username(const std::string &username, const int fd); - void _handler_client_password(const std::string &password, const int fd); - void _handler_bot_marvin(const std::string &buffer, int fd); - void _handler_bot_time(const std::string &buffer, int fd); - void _handler_bot_whois(const std::string &buffer, int fd); - void _handler_bot_whoami(const std::string &buffer, int fd); - void _handler_bot_quote(const std::string &buffer, int fd); - - void _handler_invite_only_mode(Channel* channel, bool set); - void _handler_topic_restriction_mode(Channel* channel, bool set); - void _handle_operator_privileges_mode(Channel* channel, Client* client, bool set); - void _handle_password_mode(Channel* channel, const std::string &argument, bool set); - void _handle_limit_mode(Channel* channel, Client* client, const std::string &argument, bool set, const int fd); - bool _handler_mode_flags(Channel* channel, Client* client, char mode, bool set, const std::string &arg, const int fd); - bool _parse_mode_command(const std::string &modes, Channel* channel, Client* client, const std::string &arg, const int fd); - - static bool _signal; //-> static boolean for signal - static void _signal_handler(const int signum); - - void _server_loop(); //-> server loop - void _set_server_socket(); //-> server socket creation - void _add_server_signal(); //-> server signal creation - void _accept_new_client(); //-> accept new client - void _clear_client(const int fd); //-> clear clients - void _receive_new_data(const int fd); //-> receive data from a client - void _send_response(const int fd, const std::string &response); //-> send response to client - - struct command_handler - { - std::string command; - void (Server::*handler)(const std::string &, const int); - }; - - static const int _command_list_size = 16; //-> command list size - static const command_handler _command_list[_command_list_size]; //-> command list - void _execute_command(const std::string buffer, const int fd); //-> execute command - - void _close_fds(); //-> close file descriptors - std::string _cleanse_buffer(const std::string &buffer, const std::string &chars_to_remove); //-> parse received buffer - - std::vector _split_buffer(const std::string &buffer, const std::string &delimiter); //-> split string - - Client* _get_client(const int fd); //-> get client - void _add_channel(Channel *channel); // -> add a new channel to server channels - bool _client_is_ready_to_login(const int fd); - Client* _get_client(const std::string nickname); // -> get nickname - Channel* _get_channel(const std::string &channel_name); //-> get channel - - std::string toupper(const std::string& str); + public: + Server(); + ~Server(); + // This contructor is to be used as a workaround for mockup tests + Server(std::string password, std::vector _clients, + std::vector _channels); + + void init(const std::string& port, const std::string& password); + + private: + int _port; //-> server port + int _server_fdsocket; //-> server socket file descriptor + std::string _password; //-> server password + std::vector _clients; //-> vector of clients + std::vector _fds; //-> vector of pollfd + struct sockaddr_in _server_addr; //-> server address + std::vector _channels; //-> vector of channels + + int _reply_code; // -> This a workaround to test the IRC commands without + // mocking up a client-server connection + + int get_reply_code(void); // -> Get the reply code to be checked against + // criterion test results + void _is_valid_port(const std::string& port); + bool _is_valid_nickname(const std::string& nickname); + bool _is_nickname_in_use(const int fd, const std::string& nickname); + bool _is_client_in_any_channel(const int fd); + + void _handler_client_join(const std::string& buffer, const int fd); + void _handler_client_quit(const std::string& buffer, const int fd); + void _handler_client_part(const std::string& buffer, const int fd); + void _handler_client_mode(const std::string& buffer, const int fd); + void _handler_client_kick(const std::string& buffer, const int fd); + void _handler_client_topic(const std::string& buffer, const int fd); + void _handler_client_invite(const std::string& buffer, const int fd); + void _handler_client_privmsg(const std::string& buffer, const int fd); + void _handler_client_nickname(const std::string& nickname, const int fd); + void _handler_client_username(const std::string& username, const int fd); + void _handler_client_password(const std::string& password, const int fd); + void _handler_bot_marvin(const std::string& buffer, int fd); + void _handler_bot_time(const std::string& buffer, int fd); + void _handler_bot_whois(const std::string& buffer, int fd); + void _handler_bot_whoami(const std::string& buffer, int fd); + void _handler_bot_quote(const std::string& buffer, int fd); + + void _handler_invite_only_mode(Channel* channel, bool set); + void _handler_topic_restriction_mode(Channel* channel, bool set); + void _handle_operator_privileges_mode(Channel* channel, Client* client, + bool set); + void _handle_password_mode(Channel* channel, const std::string& argument, + bool set); + void _handle_limit_mode(Channel* channel, Client* client, + const std::string& argument, bool set, + const int fd); + bool _handler_mode_flags(Channel* channel, Client* client, char mode, + bool set, const std::string& arg, const int fd); + bool _parse_mode_command(const std::string& modes, Channel* channel, + Client* client, const std::string& arg, + const int fd); + + static bool _signal; //-> static boolean for signal + static void _signal_handler(const int signum); + + void _server_loop(); //-> server loop + void _set_server_socket(); //-> server socket creation + void _add_server_signal(); //-> server signal creation + void _accept_new_client(); //-> accept new client + void _clear_client(const int fd); //-> clear clients + void _receive_new_data(const int fd); //-> receive data from a client + void _send_response( + const int fd, + const std::string& response); //-> send response to client + + struct command_handler + { + std::string command; + void (Server::*handler)(const std::string&, const int); + }; + + static const int _command_list_size = 16; //-> command list size + static const command_handler + _command_list[_command_list_size]; //-> command list + void _execute_command(const std::string buffer, + const int fd); //-> execute command + + void _close_fds(); //-> close file descriptors + std::string _cleanse_buffer( + const std::string& buffer, + const std::string& chars_to_remove); //-> parse received buffer + + std::vector _split_buffer( + const std::string& buffer, + const std::string& delimiter); //-> split string + + Client* _get_client(const int fd); //-> get client + void _add_channel( + Channel* channel); // -> add a new channel to server channels + bool _client_is_ready_to_login(const int fd); + Client* _get_client(const std::string nickname); // -> get nickname + Channel* _get_channel(const std::string& channel_name); //-> get channel + + std::string toupper(const std::string& str); }; - -#endif // SERVER_HPP \ No newline at end of file +#endif // SERVER_HPP \ No newline at end of file diff --git a/src/Channel.cpp b/src/Channel.cpp index 59f1dd7..e7adbd8 100644 --- a/src/Channel.cpp +++ b/src/Channel.cpp @@ -26,8 +26,8 @@ Channel::Channel() _name = ""; _topic = ""; _created_at = ""; - _clients = std::vector(); - _operator_clients = std::vector(); + _clients = std::vector(); + _operator_clients = std::vector(); } Channel::Channel(std::string name) @@ -40,8 +40,8 @@ Channel::Channel(std::string name) _name = name; _topic = ""; _created_at = ""; - _clients = std::vector(); - _operator_clients = std::vector(); + _clients = std::vector(); + _operator_clients = std::vector(); } /* @@ -52,7 +52,7 @@ Channel::~Channel() { this->_clients.clear(); this->_operator_clients.clear(); - return ; + return; } /* @@ -64,27 +64,21 @@ Channel::~Channel() * * @return std::string The name of the channel. */ -std::string Channel::get_name(void) const -{ - return _name; -} +std::string Channel::get_name(void) const { return _name; } /** * @brief Get the topic restriction flag of the channel. * * @return bool The topic restriction flag. */ -bool Channel::get_topic_restriction(void) const -{ - return _topic_restriction; -} +bool Channel::get_topic_restriction(void) const { return _topic_restriction; } /** * @brief Get the operator clients of the channel. * * @return std::vector The operator clients of the channel. */ -std::vector Channel::get_operator_clients(void) +std::vector Channel::get_operator_clients(void) { return this->_operator_clients; } @@ -94,7 +88,7 @@ std::vector Channel::get_operator_clients(void) * * @return std::vector The vector of clients in the channel. */ -std::vector Channel::get_channel_clients(void) +std::vector Channel::get_channel_clients(void) { return this->_clients; } @@ -102,15 +96,17 @@ std::vector Channel::get_channel_clients(void) /** * @brief Get the names of all clients in the channel. * - * This function returns a string containing the names of all clients in the channel, - * separated by a space. + * This function returns a string containing the names of all clients in the + * channel, separated by a space. * * @return std::string The names of all clients in the channel. */ std::string Channel::get_client_names(void) const { std::string names; - for (std::vector::const_iterator it = this->_clients.begin(); it != this->_clients.end(); ++it) + for (std::vector::const_iterator it = this->_clients.begin(); + it != this->_clients.end(); + ++it) { names += (*it)->get_nickname(); names += " "; @@ -123,20 +119,14 @@ std::string Channel::get_client_names(void) const * * @return The number of clients in the channel. */ -int Channel::get_clients_size(void) const -{ - return this->_clients.size(); -} +int Channel::get_clients_size(void) const { return this->_clients.size(); } /** * @brief Get the topic of the channel. * * @return std::string The topic of the channel. */ -std::string Channel::get_topic(void) const -{ - return _topic; -} +std::string Channel::get_topic(void) const { return _topic; } /** * @brief Get the channel key. @@ -145,24 +135,21 @@ std::string Channel::get_topic(void) const * * @return std::string The channel key. */ -std::string Channel::get_channel_key(void) const -{ - return _key; -} +std::string Channel::get_channel_key(void) const { return _key; } /** * @brief Sets a client as a channel operator. * - * This function sets the given client as a channel operator by setting its "is_operator" flag to true - * and adding it to the list of operator clients. + * This function sets the given client as a channel operator by setting its + * "is_operator" flag to true and adding it to the list of operator clients. * * @param client A pointer to the client to be set as a channel operator. */ -void Channel::set_channel_operator(Client *client) +void Channel::set_channel_operator(Client* client) { client->set_is_operator(true); this->_operator_clients.push_back(client); - return ; + return; } /** @@ -172,115 +159,97 @@ void Channel::set_channel_operator(Client *client) * * @param topic The new topic of the channel. */ -void Channel::set_topic(std::string topic) -{ - _topic = topic; -} +void Channel::set_topic(std::string topic) { _topic = topic; } /** * @brief Set the limit of the channel. * - * This function sets the limit of the channel, which determines the maximum number of users that can join the channel. + * This function sets the limit of the channel, which determines the maximum + * number of users that can join the channel. * * @param limit The limit of the channel. */ -void Channel::set_limit(int limit) -{ - _limit = limit; -} +void Channel::set_limit(int limit) { _limit = limit; } /** * @brief Sets the invite-only flag for the channel. * - * This function sets the invite-only flag for the channel. When the invite-only flag is set to true, - * only users who have been invited can join the channel. + * This function sets the invite-only flag for the channel. When the invite-only + * flag is set to true, only users who have been invited can join the channel. */ -void Channel::set_invite_only() -{ - _invite_only = true; -} +void Channel::set_invite_only() { _invite_only = true; } /** * @brief Sets the topic restriction flag for the channel. * - * This function sets the topic restriction flag for the channel. When the flag is set to true, - * only channel operators will be able to change the channel's topic. + * This function sets the topic restriction flag for the channel. When the flag + * is set to true, only channel operators will be able to change the channel's + * topic. */ -void Channel::set_topic_restriction() -{ - _topic_restriction = true; -} +void Channel::set_topic_restriction() { _topic_restriction = true; } /** * @brief Sets the key for the channel. * - * This function sets the key for the channel. The key is used to restrict access to the channel. + * This function sets the key for the channel. The key is used to restrict + * access to the channel. * * @param key The key to set for the channel. */ -void Channel::set_key(std::string key) -{ - _key = key; -} +void Channel::set_key(std::string key) { _key = key; } /** * @brief Removes the limit of the channel. * - * This function sets the limit of the channel to -1, indicating that there is no limit. + * This function sets the limit of the channel to -1, indicating that there is + * no limit. */ -void Channel::remove_limit(void) -{ - _limit = -1; -} +void Channel::remove_limit(void) { _limit = -1; } /** * @brief Removes the key of the channel. * - * This function sets the key of the channel to an empty string, effectively removing the key. + * This function sets the key of the channel to an empty string, effectively + * removing the key. */ -void Channel::remove_key(void) -{ - _key = ""; -} +void Channel::remove_key(void) { _key = ""; } /** * @brief Removes the topic restriction for the channel. * - * This function sets the topic restriction flag to false, allowing any user to change the channel's topic. + * This function sets the topic restriction flag to false, allowing any user to + * change the channel's topic. */ -void Channel::remove_topic_restriction(void) -{ - _topic_restriction = false; -} +void Channel::remove_topic_restriction(void) { _topic_restriction = false; } /** * @brief Removes the invite-only flag from the channel. * - * This function sets the `_invite_only` member variable of the Channel class to false, - * indicating that the channel is no longer invite-only. + * This function sets the `_invite_only` member variable of the Channel class to + * false, indicating that the channel is no longer invite-only. */ -void Channel::remove_invite_only(void) -{ - _invite_only = false; -} +void Channel::remove_invite_only(void) { _invite_only = false; } /** * @brief Removes a channel operator from the channel. * - * This function removes the specified client from the list of channel operators. - * It sets the client's "is_operator" flag to false and removes it from the "_operator_clients" vector. + * This function removes the specified client from the list of channel + * operators. It sets the client's "is_operator" flag to false and removes it + * from the "_operator_clients" vector. * * @param client A pointer to the client to be removed as a channel operator. */ -void Channel::remove_channel_operator(Client *client) +void Channel::remove_channel_operator(Client* client) { client->set_is_operator(false); - for (std::vector::iterator it = this->_operator_clients.begin(); it != this->_operator_clients.end(); ++it) + for (std::vector::iterator it = this->_operator_clients.begin(); + it != this->_operator_clients.end(); + ++it) { - if((*it)->get_nickname() == client->get_nickname()) + if ((*it)->get_nickname() == client->get_nickname()) { this->_operator_clients.erase(it); - return ; + return; } } } @@ -288,24 +257,26 @@ void Channel::remove_channel_operator(Client *client) /** * @brief Removes a client from the channel. * - * This function removes the specified client from the channel's list of clients. + * This function removes the specified client from the channel's list of + * clients. * * @param client A pointer to the client to be removed. */ -void Channel::remove_channel_client(Client *client) +void Channel::remove_channel_client(Client* client) { - for (std::vector::iterator it = this->_clients.begin(); it != this->_clients.end();) - { - if ((*it)->get_nickname() == client->get_nickname()) - { - std::cout << (*it)->get_nickname() << std::endl; - it = this->_clients.erase(it); - break ; - } - else - ++it; - } - return ; + for (std::vector::iterator it = this->_clients.begin(); + it != this->_clients.end();) + { + if ((*it)->get_nickname() == client->get_nickname()) + { + std::cout << (*it)->get_nickname() << std::endl; + it = this->_clients.erase(it); + break; + } + else + ++it; + } + return; } /* @@ -319,9 +290,11 @@ void Channel::remove_channel_client(Client *client) * @param client A pointer to the client to be checked. * @return true if the client is present in the channel, false otherwise. */ -bool Channel::has_client(Client *client) +bool Channel::has_client(Client* client) { - for (std::vector::const_iterator it = this->_clients.begin(); it != this->_clients.end(); ++it) + for (std::vector::const_iterator it = this->_clients.begin(); + it != this->_clients.end(); + ++it) { if ((*it)->get_nickname() == client->get_nickname()) return true; @@ -336,10 +309,7 @@ bool Channel::has_client(Client *client) * * @return true if the channel has a key, false otherwise. */ -bool Channel::has_key(void) const -{ - return _key != ""; -} +bool Channel::has_key(void) const { return _key != ""; } /** * @brief Checks if a given nickname belongs to a channel operator. @@ -349,7 +319,9 @@ bool Channel::has_key(void) const */ bool Channel::is_channel_operator(std::string nickname) { - for (std::vector::iterator it = _operator_clients.begin(); it != this->_operator_clients.end(); ++it) + for (std::vector::iterator it = _operator_clients.begin(); + it != this->_operator_clients.end(); + ++it) { if ((*it)->get_nickname() == nickname) return true; @@ -358,14 +330,17 @@ bool Channel::is_channel_operator(std::string nickname) } /** - * @brief Checks if a client with the given file descriptor is a channel operator. + * @brief Checks if a client with the given file descriptor is a channel + * operator. * * @param fd The file descriptor of the client. * @return true if the client is a channel operator, false otherwise. */ bool Channel::is_channel_operator(const int fd) { - for (std::vector::iterator it = _operator_clients.begin(); it != this->_operator_clients.end(); ++it) + for (std::vector::iterator it = _operator_clients.begin(); + it != this->_operator_clients.end(); + ++it) { if ((*it)->get_fd() == fd) return true; @@ -377,14 +352,15 @@ bool Channel::is_channel_operator(const int fd) /** * @brief Invites a client to the channel. * - * This function adds the specified client to the list of clients in the channel. + * This function adds the specified client to the list of clients in the + * channel. * * @param client A pointer to the client to be invited. */ -void Channel::invite(Client *client) +void Channel::invite(Client* client) { _clients.push_back(client); - return ; + return; } /** @@ -394,10 +370,10 @@ void Channel::invite(Client *client) * * @param client A pointer to the client to be added. */ -void Channel::join(Client *client) +void Channel::join(Client* client) { _clients.push_back(client); - return ; + return; } /** @@ -409,7 +385,7 @@ void Channel::join(Client *client) * * @param client A pointer to the client to be kicked. */ -void Channel::kick(Client *client) +void Channel::kick(Client* client) { client->remove_channel_invited(this->get_name()); remove_channel_operator(client); @@ -419,41 +395,49 @@ void Channel::kick(Client *client) /** * @brief Removes a client from the channel. * - * This function removes the specified client from the channel by removing them as a channel operator - * and removing them from the list of channel clients. + * This function removes the specified client from the channel by removing them + * as a channel operator and removing them from the list of channel clients. * * @param client A pointer to the client to be removed from the channel. */ -void Channel::part(Client *client) +void Channel::part(Client* client) { remove_channel_operator(client); remove_channel_client(client); } /** - * @brief Broadcasts a message to all clients in the channel, excluding the sender. + * @brief Broadcasts a message to all clients in the channel, excluding the + * sender. * - * This function iterates over the list of clients in the channel and calls the `broadcast` function - * for each client, passing the sender, target, and message as arguments. The `broadcast` function - * is called for both regular clients and operator clients. + * This function iterates over the list of clients in the channel and calls the + * `broadcast` function for each client, passing the sender, target, and message + * as arguments. The `broadcast` function is called for both regular clients and + * operator clients. * * @param sender A pointer to the client who sent the message. * @param target The target of the message. * @param message The message to be broadcasted. */ -void Channel::broadcast(Client *sender, std::string target, std::string message) +void Channel::broadcast(Client* sender, std::string target, std::string message) { - for (std::vector::iterator it = this->_clients.begin(); it != this->_clients.end(); it++) { + for (std::vector::iterator it = this->_clients.begin(); + it != this->_clients.end(); + it++) + { if (*it == sender) - continue ; + continue; (*it)->broadcast(sender, target, message); } - for (std::vector::iterator it = this->_operator_clients.begin(); it != this->_operator_clients.end(); it++) { + for (std::vector::iterator it = this->_operator_clients.begin(); + it != this->_operator_clients.end(); + it++) + { if (*it == sender) - continue ; + continue; (*it)->broadcast(sender, target, message); } - return ; + return; } /** @@ -464,9 +448,11 @@ void Channel::broadcast(Client *sender, std::string target, std::string message) */ bool Channel::is_client_in_channel(std::string nickname) { - for (std::vector::iterator it = this->_clients.begin(); it != this->_clients.end(); ++it) + for (std::vector::iterator it = this->_clients.begin(); + it != this->_clients.end(); + ++it) { - if((*it)->get_nickname() == nickname) + if ((*it)->get_nickname() == nickname) return true; } return false; @@ -492,11 +478,9 @@ bool Channel::is_channel_full(void) const /** * @brief Check if the channel is invite-only. * - * This function returns a boolean value indicating whether the channel is invite-only or not. + * This function returns a boolean value indicating whether the channel is + * invite-only or not. * * @return true if the channel is invite-only, false otherwise. */ -bool Channel::is_channel_invite_only(void) const -{ - return _invite_only; -} +bool Channel::is_channel_invite_only(void) const { return _invite_only; } diff --git a/src/Client.cpp b/src/Client.cpp index f20ef43..8dded72 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -39,10 +39,7 @@ Client::Client() * * @param fd The file descriptor to set. */ -void Client::set_fd(const int fd) -{ - _fd = fd; -} +void Client::set_fd(const int fd) { _fd = fd; } /** * @brief Sets the IP address for the client. @@ -51,20 +48,14 @@ void Client::set_fd(const int fd) * * @param ipadd The IP address to set. */ -void Client::set_ip_add(const std::string &ipadd) -{ - _ip_addr = ipadd; -} +void Client::set_ip_add(const std::string& ipadd) { _ip_addr = ipadd; } /** * @brief Get the IP address of the client. * * @return std::string The IP address of the client. */ -std::string Client::get_ip_address() const -{ - return _ip_addr; -} +std::string Client::get_ip_address() const { return _ip_addr; } /** * @brief Sets the buffer of the client. @@ -73,10 +64,7 @@ std::string Client::get_ip_address() const * * @param buffer The new buffer value. */ -void Client::set_buffer(const std::string &buffer) -{ - _buffer = buffer; -} +void Client::set_buffer(const std::string& buffer) { _buffer = buffer; } /** * @brief Sets the nickname of the client. @@ -85,10 +73,7 @@ void Client::set_buffer(const std::string &buffer) * * @param nickname The nickname to set. */ -void Client::set_nickname(const std::string &nickname) -{ - _nickname = nickname; -} +void Client::set_nickname(const std::string& nickname) { _nickname = nickname; } /** * @brief Sets the username of the client. @@ -97,28 +82,23 @@ void Client::set_nickname(const std::string &nickname) * * @param username The username to set. */ -void Client::set_username(const std::string &username) -{ - _username = username; -} +void Client::set_username(const std::string& username) { _username = username; } /** * @brief Sets the password for the client. * - * This function sets the password for the client. The password is used for authentication - * purposes when connecting to a server. + * This function sets the password for the client. The password is used for + * authentication purposes when connecting to a server. * * @param password The password to set. */ -void Client::set_password(const std::string &password) -{ - _password = password; -} +void Client::set_password(const std::string& password) { _password = password; } /** * @brief Sets the authentication status of the client. * - * This function sets the authentication status of the client to the specified value. + * This function sets the authentication status of the client to the specified + * value. * * @param is_authenticated The authentication status to set. */ @@ -130,15 +110,13 @@ void Client::set_is_authenticated(bool is_authenticated) /** * @brief Sets the operator status of the client. * - * This function sets the operator status of the client. An operator is a user with special privileges - * and permissions in the IRC server. + * This function sets the operator status of the client. An operator is a user + * with special privileges and permissions in the IRC server. * - * @param is_operator A boolean value indicating whether the client is an operator or not. + * @param is_operator A boolean value indicating whether the client is an + * operator or not. */ -void Client::set_is_operator(bool is_operator) -{ - _is_operator = is_operator; -} +void Client::set_is_operator(bool is_operator) { _is_operator = is_operator; } /** * @brief Sets the logged status of the client. @@ -147,104 +125,76 @@ void Client::set_is_operator(bool is_operator) * * @param is_logged The new logged status of the client. */ -void Client::set_is_logged(bool is_logged) -{ - _is_logged = is_logged; -} +void Client::set_is_logged(bool is_logged) { _is_logged = is_logged; } /** * @brief Get the authentication status of the client. * * @return true if the client is authenticated, false otherwise. */ -bool Client::get_is_authenticated() const -{ - return _is_authenticated; -} +bool Client::get_is_authenticated() const { return _is_authenticated; } /** * @brief Get the operator status of the client. * * @return true if the client is an operator, false otherwise. */ -bool Client::get_is_operator() const -{ - return _is_operator; -} +bool Client::get_is_operator() const { return _is_operator; } /** * @brief Get the logged status of the client. * * @return true if the client is logged in, false otherwise. */ -bool Client::get_is_logged() const -{ - return _is_logged; -} +bool Client::get_is_logged() const { return _is_logged; } /** * @brief Get the file descriptor of the client. * * @return The file descriptor of the client. */ -int Client::get_fd() const -{ - return _fd; -} +int Client::get_fd() const { return _fd; } /** * @brief Get the buffer of the client. * - * This function returns the buffer of the client, which contains the received data. + * This function returns the buffer of the client, which contains the received + * data. * * @return std::string The buffer of the client. */ -std::string Client::get_buffer() const -{ - return _buffer; -} +std::string Client::get_buffer() const { return _buffer; } /** * @brief Get the nickname of the client. * * @return std::string The nickname of the client. */ -std::string Client::get_nickname() const -{ - return _nickname; -} +std::string Client::get_nickname() const { return _nickname; } /** * @brief Get the username of the client. * * @return std::string The username of the client. */ -std::string Client::get_username() const -{ - return _username; -} +std::string Client::get_username() const { return _username; } /** * @brief Get the password of the client. * * @return std::string The password of the client. */ -std::string Client::get_password() const -{ - return _password; -} +std::string Client::get_password() const { return _password; } /** * @brief Get the hostname of the client. * - * This function returns the hostname of the client by concatenating the nickname and IP address. + * This function returns the hostname of the client by concatenating the + * nickname and IP address. * * @return std::string The hostname of the client. */ -std::string Client::get_hostname() const -{ - return _nickname + "@" + _ip_addr; -} +std::string Client::get_hostname() const { return _nickname + "@" + _ip_addr; } /** * @brief Get the list of channels the client has been invited to. @@ -272,25 +222,28 @@ std::vector Client::get_channels_invited() const * * @param channel The name of the channel to be removed. */ -void Client::remove_channel_invited(const std::string &channel) +void Client::remove_channel_invited(const std::string& channel) { std::vector::iterator it; - for (it = _channels_invited.begin(); it != _channels_invited.end(); ++it) { - if (*it == channel) { - _channels_invited.erase(it); - break; - } - } + for (it = _channels_invited.begin(); it != _channels_invited.end(); ++it) + { + if (*it == channel) + { + _channels_invited.erase(it); + break; + } + } } /** * @brief Adds a channel to the list of invited channels. * - * This function adds the specified channel to the list of channels that the client has been invited to. + * This function adds the specified channel to the list of channels that the + * client has been invited to. * * @param channel The name of the channel to be added. */ -void Client::add_channel_invited(const std::string &channel) +void Client::add_channel_invited(const std::string& channel) { _channels_invited.push_back(channel); } @@ -303,23 +256,26 @@ void Client::add_channel_invited(const std::string &channel) * @param channel The name of the channel to check. * @return True if the client is invited to the channel, false otherwise. */ -bool Client::is_channel_invited(const std::string &channel) +bool Client::is_channel_invited(const std::string& channel) { - return std::find(_channels_invited.begin(), _channels_invited.end(), channel) != _channels_invited.end(); + return std::find(_channels_invited.begin(), + _channels_invited.end(), + channel) != _channels_invited.end(); } /** * @brief Sends a broadcast message from the client to a target. * - * This function constructs a response message using the sender's hostname, target, and message. - * It then sends the response message to the client's file descriptor using the send() function. - * If the send() function fails, an error message is printed to the standard error stream. + * This function constructs a response message using the sender's hostname, + * target, and message. It then sends the response message to the client's file + * descriptor using the send() function. If the send() function fails, an error + * message is printed to the standard error stream. * * @param sender A pointer to the client sending the broadcast message. * @param target The target of the broadcast message. * @param message The content of the broadcast message. */ -void Client::broadcast(Client *sender, std::string target, std::string message) +void Client::broadcast(Client* sender, std::string target, std::string message) { std::string response = RPL_PRIVMSG(sender->get_hostname(), target, message); diff --git a/src/MarvinBot.cpp b/src/MarvinBot.cpp index 976993e..3ced82b 100644 --- a/src/MarvinBot.cpp +++ b/src/MarvinBot.cpp @@ -13,33 +13,29 @@ #include "MarvinBot.hpp" // Constructor -MarvinBot::MarvinBot() -{ -} +MarvinBot::MarvinBot() {} // Destructor -MarvinBot::~MarvinBot() -{ -} +MarvinBot::~MarvinBot() {} /** * @brief Array of quotes used by the MarvinBot class. * - * This array stores the quotes used by the MarvinBot class. Each quote is represented as a C-style string. - * The quotes are accessed using the predefined constants in the MarvinBot class. + * This array stores the quotes used by the MarvinBot class. Each quote is + * represented as a C-style string. The quotes are accessed using the predefined + * constants in the MarvinBot class. */ const char* marvin_bot_quotes[MarvinBot::QUOTES_COUNT] = { - SOCRATES_KNOWLEDGE, - DESCARTES_EXISTENCE, - KANT_CATEGORICAL_IMPERATIVE, - NIETZSCHE_GOD, - PLATO_FORMS, - MARX_RELIGION, - CONFUCIUS_WISDOM, - HUME_SCIENCE, - HEIDEGGER_BEING, - ROUSSEAU_FREEDOM -}; + SOCRATES_KNOWLEDGE, + DESCARTES_EXISTENCE, + KANT_CATEGORICAL_IMPERATIVE, + NIETZSCHE_GOD, + PLATO_FORMS, + MARX_RELIGION, + CONFUCIUS_WISDOM, + HUME_SCIENCE, + HEIDEGGER_BEING, + ROUSSEAU_FREEDOM}; /** * @brief Generates and returns a random quote from the list of quotes. @@ -48,27 +44,30 @@ const char* marvin_bot_quotes[MarvinBot::QUOTES_COUNT] = { */ std::string _return_quote() { - srand(time(0)); - int index = rand() % MarvinBot::QUOTES_COUNT; + srand(time(0)); + int index = rand() % MarvinBot::QUOTES_COUNT; - return std::string(marvin_bot_quotes[index]); + return std::string(marvin_bot_quotes[index]); } /* -** ------------------------------- COMMAND HANDLERS -------------------------------- +** ------------------------------- COMMAND HANDLERS +*-------------------------------- */ /** * Handles the bot command "marvin" for a specific client. * - * This function is responsible for processing the "marvin" command received from a client. - * It checks if the client is logged in and if they are already in any channel. Depending on the - * client's state, it sends the appropriate response back to the client. + * This function is responsible for processing the "marvin" command received + * from a client. It checks if the client is logged in and if they are already + * in any channel. Depending on the client's state, it sends the appropriate + * response back to the client. * - * @param buffer The command buffer received from the client (not used in this function). + * @param buffer The command buffer received from the client (not used in this + * function). * @param fd The file descriptor of the client's socket connection. */ -void Server::_handler_bot_marvin(const std::string &/* buffer */, int fd) +void Server::_handler_bot_marvin(const std::string& /* buffer */, int fd) { Client* client = _get_client(fd); @@ -85,23 +84,25 @@ void Server::_handler_bot_marvin(const std::string &/* buffer */, int fd) } else { - this->_send_response(fd, BOT_CLIENTNOTINCHANNEL(client->get_nickname())); - _reply_code = 2424; - } + this->_send_response(fd, + BOT_CLIENTNOTINCHANNEL(client->get_nickname())); + _reply_code = 2424; + } } /** * Handles the bot time command. * - * This function is responsible for handling the bot time command received from a client. - * It checks if the client is logged in and if they are in any channel. If the client is - * not registered, it sends an error response. If the client is registered and in a channel, - * it sends the current time to the client. + * This function is responsible for handling the bot time command received from + * a client. It checks if the client is logged in and if they are in any + * channel. If the client is not registered, it sends an error response. If the + * client is registered and in a channel, it sends the current time to the + * client. * * @param buffer The command buffer received from the client. * @param fd The file descriptor of the client's socket. */ -void Server::_handler_bot_time(const std::string &/* buffer */, int fd) +void Server::_handler_bot_time(const std::string& /* buffer */, int fd) { Client* client = _get_client(fd); @@ -118,18 +119,20 @@ void Server::_handler_bot_time(const std::string &/* buffer */, int fd) this->_send_response(fd, BOT_CMDTIME(client->get_nickname(), time_str)); } else - this->_send_response(fd, BOT_CLIENTNOTINCHANNEL(client->get_nickname())); + this->_send_response(fd, + BOT_CLIENTNOTINCHANNEL(client->get_nickname())); } /** * Handles the "bot_whoami" command. - * This function is responsible for processing the "bot_whoami" command received from a client. - * It checks if the client is logged in and sends the appropriate response based on the client's status. + * This function is responsible for processing the "bot_whoami" command received + * from a client. It checks if the client is logged in and sends the appropriate + * response based on the client's status. * * @param buffer The command buffer (not used in this function). * @param fd The file descriptor of the client. */ -void Server::_handler_bot_whoami(const std::string &/* buffer */, int fd) +void Server::_handler_bot_whoami(const std::string& /* buffer */, int fd) { Client* client = _get_client(fd); @@ -140,32 +143,38 @@ void Server::_handler_bot_whoami(const std::string &/* buffer */, int fd) return; } else if (this->_is_client_in_any_channel(fd)) - this->_send_response(fd, BOT_CMDWHOIS(client->get_nickname(), client->get_username(), client->get_ip_address())); + this->_send_response(fd, + BOT_CMDWHOIS(client->get_nickname(), + client->get_username(), + client->get_ip_address())); else - this->_send_response(fd, BOT_CLIENTNOTINCHANNEL(client->get_nickname())); + this->_send_response(fd, + BOT_CLIENTNOTINCHANNEL(client->get_nickname())); } /** * @brief Handles the BOT_WHOIS command from the server. * - * This function is responsible for processing the BOT_WHOIS command received from the server. - * It extracts the nickname from the buffer and retrieves the corresponding client object. - * If the client is not logged in, it sends an error response. - * If the client is logged in and is in a channel, it sends a response with the client's information. - * If the client is logged in but not in a channel, it sends a response indicating that the client is not in a channel. - * If the client does not exist, it sends a response indicating that the client does not exist. + * This function is responsible for processing the BOT_WHOIS command received + * from the server. It extracts the nickname from the buffer and retrieves the + * corresponding client object. If the client is not logged in, it sends an + * error response. If the client is logged in and is in a channel, it sends a + * response with the client's information. If the client is logged in but not in + * a channel, it sends a response indicating that the client is not in a + * channel. If the client does not exist, it sends a response indicating that + * the client does not exist. * * @param buffer The buffer containing the command and its arguments. * @param fd The file descriptor of the client connection. */ -void Server::_handler_bot_whois(const std::string &buffer, int fd) +void Server::_handler_bot_whois(const std::string& buffer, int fd) { std::istringstream iss(buffer); std::string nickname; iss >> nickname; - Client *client = _get_client(fd); - Client *whois = _get_client(nickname); + Client* client = _get_client(fd); + Client* whois = _get_client(nickname); if (!client->get_is_logged()) { @@ -175,23 +184,29 @@ void Server::_handler_bot_whois(const std::string &buffer, int fd) } else if (this->_is_client_in_any_channel(fd)) if (whois) - this->_send_response(fd, BOT_CMDWHOIS(whois->get_nickname(), whois->get_username(), whois->get_ip_address())); + this->_send_response(fd, + BOT_CMDWHOIS(whois->get_nickname(), + whois->get_username(), + whois->get_ip_address())); else - this->_send_response(fd, BOT_WHOISDOESNTEXIST(client->get_nickname())); + this->_send_response(fd, + BOT_WHOISDOESNTEXIST(client->get_nickname())); else - this->_send_response(fd, BOT_CLIENTNOTINCHANNEL(client->get_nickname())); + this->_send_response(fd, + BOT_CLIENTNOTINCHANNEL(client->get_nickname())); } /** * Handles the bot quote command. * - * This function is responsible for handling the bot quote command received from a client. - * It checks if the client is logged in and sends an appropriate response based on the client's status. + * This function is responsible for handling the bot quote command received from + * a client. It checks if the client is logged in and sends an appropriate + * response based on the client's status. * * @param buffer The command buffer received from the client. * @param fd The file descriptor of the client's connection. */ -void Server::_handler_bot_quote(const std::string &/* buffer */, int fd) +void Server::_handler_bot_quote(const std::string& /* buffer */, int fd) { Client* client = _get_client(fd); @@ -202,7 +217,9 @@ void Server::_handler_bot_quote(const std::string &/* buffer */, int fd) return; } else if (this->_is_client_in_any_channel(fd)) - this->_send_response(fd, BOT_CMDQUOTE(client->get_nickname(), _return_quote())); + this->_send_response( + fd, BOT_CMDQUOTE(client->get_nickname(), _return_quote())); else - this->_send_response(fd, BOT_CLIENTNOTINCHANNEL(client->get_nickname())); + this->_send_response(fd, + BOT_CLIENTNOTINCHANNEL(client->get_nickname())); } diff --git a/src/Server.cpp b/src/Server.cpp index 4e33123..c34d91e 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -29,11 +29,9 @@ Server::Server() Server::~Server() { this->_channels.clear(); - return ; + return; } - - /* ** ------------------------------- GETTERS -------------------------------- */ @@ -41,17 +39,20 @@ Server::~Server() /** * @brief Retrieves the client associated with the given file descriptor. * - * This method retrieves the client object associated with the specified file descriptor from the - * vector of active clients. It iterates through the list of clients and returns the client object - * that matches the provided file descriptor. + * This method retrieves the client object associated with the specified file + * descriptor from the vector of active clients. It iterates through the list of + * clients and returns the client object that matches the provided file + * descriptor. * * @param fd The file descriptor associated with the client to retrieve. * @return The client object associated with the specified file descriptor. */ Client* Server::_get_client(const int fd) { - for (size_t i = 0; i < _clients.size(); i++) { - if (_clients[i].get_fd() == fd) { + for (size_t i = 0; i < _clients.size(); i++) + { + if (_clients[i].get_fd() == fd) + { return &_clients[i]; } } @@ -71,8 +72,10 @@ Client* Server::_get_client(const int fd) */ Client* Server::_get_client(const std::string nickname) { - for (size_t i = 0; i < _clients.size(); i++) { - if (_clients[i].get_nickname() == nickname) { + for (size_t i = 0; i < _clients.size(); i++) + { + if (_clients[i].get_nickname() == nickname) + { return &_clients[i]; } } @@ -90,10 +93,12 @@ Client* Server::_get_client(const std::string nickname) * @param channel_name The name of the channel to retrieve. * @return A pointer to the channel object if found, otherwise a null pointer. */ -Channel* Server::_get_channel(const std::string &channel_name) +Channel* Server::_get_channel(const std::string& channel_name) { - for (size_t i = 0; i < _channels.size(); i++) { - if (_channels[i]->get_name() == channel_name) { + for (size_t i = 0; i < _channels.size(); i++) + { + if (_channels[i]->get_name() == channel_name) + { return _channels[i]; } } @@ -103,15 +108,13 @@ Channel* Server::_get_channel(const std::string &channel_name) /** * @brief Adds a new channel to the server. * - * This function adds a new channel to the list of channels maintained by the server. - * The channel object is created with the specified name and added to the list of channels. + * This function adds a new channel to the list of channels maintained by the + * server. The channel object is created with the specified name and added to + * the list of channels. * * @param channel The name of the channel to be added. */ -void Server::_add_channel(Channel *channel) -{ - _channels.push_back(channel); -} +void Server::_add_channel(Channel* channel) { _channels.push_back(channel); } /** * @brief Checks if the client is in any channel. @@ -121,10 +124,7 @@ void Server::_add_channel(Channel *channel) * @param fd The file descriptor associated with the client. * @return True if the client is in any channel, false otherwise. */ -int Server::get_reply_code(void) -{ - return _reply_code; -} +int Server::get_reply_code(void) { return _reply_code; } /* ** ------------------------------- SETTERS -------------------------------- @@ -133,9 +133,10 @@ int Server::get_reply_code(void) /** * @brief Sets up the server socket for the server. * - * This function creates a socket, sets the socket options, sets the socket to non-blocking mode, - * binds the socket to the specified address and port, and starts listening for incoming connections. - * The server socket is added to the list of file descriptors for polling. + * This function creates a socket, sets the socket options, sets the socket to + * non-blocking mode, binds the socket to the specified address and port, and + * starts listening for incoming connections. The server socket is added to the + * list of file descriptors for polling. * * * This method initializes the server by performing the following steps: * 1. Creates a server socket. @@ -158,13 +159,21 @@ void Server::_set_server_socket() server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(_port); _server_fdsocket = socket(AF_INET, SOCK_STREAM, 0); - if(_server_fdsocket == -1) + if (_server_fdsocket == -1) throw(std::runtime_error("failed to create socket")); - if(setsockopt(_server_fdsocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) - throw(std::runtime_error("failed to set option (SO_REUSEADDR) on socket")); + if (setsockopt(_server_fdsocket, + SOL_SOCKET, + SO_REUSEADDR, + &enable, + sizeof(enable)) == -1) + throw(std::runtime_error( + "failed to set option (SO_REUSEADDR) on socket")); if (fcntl(_server_fdsocket, F_SETFL, O_NONBLOCK) == -1) - throw(std::runtime_error("failed to set option (O_NONBLOCK) on socket")); - if (bind(_server_fdsocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) + throw( + std::runtime_error("failed to set option (O_NONBLOCK) on socket")); + if (bind(_server_fdsocket, + (struct sockaddr*)&server_addr, + sizeof(server_addr)) == -1) throw(std::runtime_error("failed to bind socket")); if (listen(_server_fdsocket, SOMAXCONN) == -1) throw(std::runtime_error("listen() failed")); @@ -182,7 +191,8 @@ void Server::_set_server_socket() * @brief Initializes the server. * * This method initializes the server by setting the server port and password, - * adding the server signal, creating the server socket, and starting the server loop. + * adding the server signal, creating the server socket, and starting the server + * loop. * * @param port The server port. * @param password The server password. @@ -190,7 +200,7 @@ void Server::_set_server_socket() * @throws std::invalid_argument if the port is invalid. * @throws std::runtime_error if an error occurs during server initialization. */ -void Server::init(const std::string &port, const std::string &password) +void Server::init(const std::string& port, const std::string& password) { _is_valid_port(port); @@ -207,7 +217,7 @@ void Server::init(const std::string &port, const std::string &password) _server_loop(); _close_fds(); } - catch(const std::exception& e) + catch (const std::exception& e) { _close_fds(); std::cerr << e.what() << '\n'; @@ -217,9 +227,9 @@ void Server::init(const std::string &port, const std::string &password) /** * @brief Starts the server loop. * - * This method initiates the server loop, continuously waiting for incoming connections - * and processing data received from clients. It utilizes the poll system call to efficiently - * monitor file descriptors for events. + * This method initiates the server loop, continuously waiting for incoming + * connections and processing data received from clients. It utilizes the poll + * system call to efficiently monitor file descriptors for events. * * The server loop continues to run until a termination signal is received. * @@ -229,10 +239,12 @@ void Server::_server_loop() { while (Server::_signal == false) { - if((poll(&_fds[0], _fds.size(), -1) == -1) && Server::_signal == false) + if ((poll(&_fds[0], _fds.size(), -1) == -1) && Server::_signal == false) throw(std::runtime_error("poll() faild")); - for (size_t i = 0; i < _fds.size(); i++) { - if (_fds[i].revents & POLLIN) { + for (size_t i = 0; i < _fds.size(); i++) + { + if (_fds[i].revents & POLLIN) + { if (_fds[i].fd == _server_fdsocket) _accept_new_client(); else @@ -245,13 +257,15 @@ void Server::_server_loop() /** * @brief Accepts a new client connection. * - * This method is called when a new client connection is detected by the server. It accepts - * the incoming connection, sets it to non-blocking mode, and adds the client socket to the - * list of active clients for polling. Additionally, it retrieves the IP address of the client - * and associates it with the client object. + * This method is called when a new client connection is detected by the server. + * It accepts the incoming connection, sets it to non-blocking mode, and adds + * the client socket to the list of active clients for polling. Additionally, it + * retrieves the IP address of the client and associates it with the client + * object. * - * @note If the acceptance of the new client connection fails or setting the socket to non-blocking mode - * fails, appropriate error messages are printed to the standard output, and the function returns. + * @note If the acceptance of the new client connection fails or setting the + * socket to non-blocking mode fails, appropriate error messages are printed to + * the standard output, and the function returns. */ void Server::_accept_new_client() { @@ -261,11 +275,17 @@ void Server::_accept_new_client() memset(&cli_addr, 0, sizeof(cli_addr)); socklen_t len = sizeof(cli_addr); - int incofd = accept(_server_fdsocket, (sockaddr *)&(cli_addr), &len); + int incofd = accept(_server_fdsocket, (sockaddr*)&(cli_addr), &len); if (incofd == -1) - {std::cout << "accept() failed" << std::endl; return;} + { + std::cout << "accept() failed" << std::endl; + return; + } if (fcntl(incofd, F_SETFL, O_NONBLOCK) == -1) - {std::cout << "fcntl() failed" << std::endl; return;} + { + std::cout << "fcntl() failed" << std::endl; + return; + } new_poll.fd = incofd; new_poll.events = POLLIN; new_poll.revents = 0; @@ -273,15 +293,17 @@ void Server::_accept_new_client() cli.set_ip_add(inet_ntoa((cli_addr.sin_addr))); _clients.push_back(cli); _fds.push_back(new_poll); - std::cout << GRE << "Client <" << incofd << "> Connected" << WHI << std::endl; + std::cout << GRE << "Client <" << incofd << "> Connected" << WHI + << std::endl; } /** * @brief Receives new data from the client. * - * This method is called when new data is received from the client. It reads the data from the client - * socket, processes the command, and executes the corresponding action. If the client disconnects - * during the data transfer, the client is removed from the list of active clients. + * This method is called when new data is received from the client. It reads the + * data from the client socket, processes the command, and executes the + * corresponding action. If the client disconnects during the data transfer, the + * client is removed from the list of active clients. * * @param fd The file descriptor associated with the client that sent the data. */ @@ -291,12 +313,15 @@ void Server::_receive_new_data(const int fd) std::memset(buffer, 0, sizeof(buffer)); Client* cli = _get_client(fd); - ssize_t bytes = recv(fd, buffer, sizeof(buffer) -1 , 0); - if(bytes <= 0) { - std::cout << RED << "Client <" << fd << "> Disconnected" << WHI << std::endl; + ssize_t bytes = recv(fd, buffer, sizeof(buffer) - 1, 0); + if (bytes <= 0) + { + std::cout << RED << "Client <" << fd << "> Disconnected" << WHI + << std::endl; _clear_client(fd); } - else { + else + { cli->set_buffer(buffer); if (cli->get_buffer().find_first_of(LINE_FEED) == std::string::npos) return; @@ -308,10 +333,12 @@ void Server::_receive_new_data(const int fd) * @brief Array of command handlers for the Server class. * * This array maps command names to their corresponding handler functions. - * Each element of the array is a struct containing the command name and a pointer to the handler function. + * Each element of the array is a struct containing the command name and a + * pointer to the handler function. * * The command handlers are used to process incoming commands from clients. - * When a command is received, the server looks up the corresponding handler function in this array and calls it. + * When a command is received, the server looks up the corresponding handler + * function in this array and calls it. * * The command list is defined as a static member of the Server class. * @@ -345,23 +372,25 @@ const Server::command_handler Server::_command_list[_command_list_size] = { {"PASS", &Server::_handler_client_password}, {"INVITE", &Server::_handler_client_invite}, {"PRIVMSG", &Server::_handler_client_privmsg}, - {"!MARVIN", &Server::_handler_bot_marvin}, - {"!TIME", &Server::_handler_bot_time}, + {"!MARVIN", &Server::_handler_bot_marvin}, + {"!TIME", &Server::_handler_bot_time}, {"!WHOIS", &Server::_handler_bot_whois}, - {"!WHOAMI", &Server::_handler_bot_whoami}, + {"!WHOAMI", &Server::_handler_bot_whoami}, {"!QUOTE", &Server::_handler_bot_quote}, }; /** * @brief Executes a command received from a client. * - * This function takes a buffer containing a command received from a client and executes it. - * The buffer is first cleansed by removing any carriage return and line feed characters. - * Then, the buffer is split into a vector of strings using a delimiter. - * The first element of the vector is considered the command, which is converted to uppercase. - * The second element of the vector is considered the parameters for the command. - * The function then iterates through a command list and checks if the command matches any of the commands in the list. - * If a match is found, the corresponding command handler is called with the parameters and the file descriptor of the client. + * This function takes a buffer containing a command received from a client and + * executes it. The buffer is first cleansed by removing any carriage return and + * line feed characters. Then, the buffer is split into a vector of strings + * using a delimiter. The first element of the vector is considered the command, + * which is converted to uppercase. The second element of the vector is + * considered the parameters for the command. The function then iterates through + * a command list and checks if the command matches any of the commands in the + * list. If a match is found, the corresponding command handler is called with + * the parameters and the file descriptor of the client. * * @param buffer The buffer containing the command received from the client. * @param fd The file descriptor of the client. @@ -369,16 +398,19 @@ const Server::command_handler Server::_command_list[_command_list_size] = { void Server::_execute_command(const std::string buffer, const int fd) { if (buffer.empty()) - return ; + return; std::string clean_buffer = _cleanse_buffer(buffer, CRLF); - std::vector splitted_buffer = _split_buffer(clean_buffer, DELIMITER); + std::vector splitted_buffer = + _split_buffer(clean_buffer, DELIMITER); if (splitted_buffer.empty()) - return ; + return; std::string command = toupper(splitted_buffer[0]); std::string parameters = splitted_buffer[1]; - for (size_t i = 0; i < _command_list_size; i++) { - if (command == _command_list[i].command) { + for (size_t i = 0; i < _command_list_size; i++) + { + if (command == _command_list[i].command) + { (this->*_command_list[i].handler)(parameters, fd); break; } @@ -386,51 +418,57 @@ void Server::_execute_command(const std::string buffer, const int fd) } /* -** ------------------------------- PARSER COMMAND -------------------------------- +** ------------------------------- PARSER COMMAND +*-------------------------------- */ /** * @brief Splits a string into tokens using a delimiter. * - * This function takes a string and a delimiter as input and splits the string into tokens based on the delimiter. - * The first token is stored as the command, and the remaining part of the string is stored as the parameters. - * The tokens are then returned as a vector of strings. + * This function takes a string and a delimiter as input and splits the string + * into tokens based on the delimiter. The first token is stored as the command, + * and the remaining part of the string is stored as the parameters. The tokens + * are then returned as a vector of strings. * * @param buffer The string to be split. * @param delimiter The delimiter used to split the string. - * @return std::vector The vector of tokens obtained after splitting the string. + * @return std::vector The vector of tokens obtained after + * splitting the string. */ -std::vector Server::_split_buffer(const std::string &buffer, const std::string &delimiter) +std::vector Server::_split_buffer(const std::string& buffer, + const std::string& delimiter) { - std::string command; - std::string parameters; - std::vector tokens; - std::istringstream iss(buffer); - + std::string command; + std::string parameters; + std::vector tokens; + std::istringstream iss(buffer); - iss >> command; - tokens.push_back(command); + iss >> command; + tokens.push_back(command); - std::getline(iss >> std::ws, parameters); - parameters.erase(0, parameters.find_first_not_of(delimiter)); - tokens.push_back(parameters); + std::getline(iss >> std::ws, parameters); + parameters.erase(0, parameters.find_first_not_of(delimiter)); + tokens.push_back(parameters); - return tokens; + return tokens; } /** * @brief Cleanses the given buffer by removing specified characters. * - * This function takes a buffer string and removes all the characters specified in the 'chars_to_remove' string. - * It returns the cleansed buffer string. + * This function takes a buffer string and removes all the characters specified + * in the 'chars_to_remove' string. It returns the cleansed buffer string. * * @param buffer The buffer string to be cleansed. - * @param chars_to_remove The string containing characters to be removed from the buffer. + * @param chars_to_remove The string containing characters to be removed from + * the buffer. * @return The cleansed buffer string. -* @note This function assumes that `original_str` is not empty and contains at least one character to be removed. -* If `chars_to_remove` is empty, the function returns the original string without any changes. + * @note This function assumes that `original_str` is not empty and contains at + * least one character to be removed. If `chars_to_remove` is empty, the + * function returns the original string without any changes. */ -std::string Server::_cleanse_buffer(const std::string &buffer, const std::string &chars_to_remove) +std::string Server::_cleanse_buffer(const std::string& buffer, + const std::string& chars_to_remove) { std::string clean_buffer; @@ -443,17 +481,20 @@ std::string Server::_cleanse_buffer(const std::string &buffer, const std::string } /* -** ------------------------------- CLEAR FUCTIONS -------------------------------- +** ------------------------------- CLEAR FUCTIONS +*-------------------------------- */ /** - * @brief Closes all file descriptors associated with the server and its clients. + * @brief Closes all file descriptors associated with the server and its + * clients. * - * This function closes all the file descriptors associated with the server and its clients. - * It iterates through the clients vector and closes each client's file descriptor. - * It also closes the server's file descriptor if it is valid. + * This function closes all the file descriptors associated with the server and + * its clients. It iterates through the clients vector and closes each client's + * file descriptor. It also closes the server's file descriptor if it is valid. * - * @note This function does not handle any exceptions that may occur during the closing of file descriptors. + * @note This function does not handle any exceptions that may occur during the + * closing of file descriptors. * * @param None * @return None @@ -463,36 +504,44 @@ std::string Server::_cleanse_buffer(const std::string &buffer, const std::string */ void Server::_close_fds() { - for(size_t i = 0; i < _clients.size(); i++) { - std::cout << RED << "Client <" << _clients[i].get_fd() << "> Disconnected" << WHI << std::endl; + for (size_t i = 0; i < _clients.size(); i++) + { + std::cout << RED << "Client <" << _clients[i].get_fd() + << "> Disconnected" << WHI << std::endl; close(_clients[i].get_fd()); } - if (_server_fdsocket != -1) { - std::cout << RED << "Server <" << _server_fdsocket << "> Disconnected" << WHI << std::endl; + if (_server_fdsocket != -1) + { + std::cout << RED << "Server <" << _server_fdsocket << "> Disconnected" + << WHI << std::endl; close(_server_fdsocket); } } - /** * @brief Clears a client from the server. * - * This function removes the client with the specified file descriptor (fd) from the server's internal data structures. - * It removes the file descriptor from the _fds vector and the corresponding client object from the _clients vector. + * This function removes the client with the specified file descriptor (fd) from + * the server's internal data structures. It removes the file descriptor from + * the _fds vector and the corresponding client object from the _clients vector. * Finally, it closes the file descriptor. * * @param fd The file descriptor of the client to be cleared. */ void Server::_clear_client(const int fd) { - for(size_t i = 0; i < _fds.size(); i++) { - if (_fds[i].fd == fd){ + for (size_t i = 0; i < _fds.size(); i++) + { + if (_fds[i].fd == fd) + { _fds.erase(_fds.begin() + i); break; } } - for(size_t i = 0; i < _clients.size(); i++) { - if (_clients[i].get_fd() == fd) { + for (size_t i = 0; i < _clients.size(); i++) + { + if (_clients[i].get_fd() == fd) + { _clients.erase(_clients.begin() + i); break; } @@ -501,14 +550,16 @@ void Server::_clear_client(const int fd) } /* -** ------------------------------- SIGNAL FUCTIONS -------------------------------- +** ------------------------------- SIGNAL FUCTIONS +*-------------------------------- */ bool Server::_signal = false; /** * @brief Signal handler function for the Server class. * - * This function is called when a signal is received by the server. It sets the static boolean + * This function is called when a signal is received by the server. It sets the + * static boolean * `_signal` to true, indicating that the server should stop. * * @param signum The signal number. @@ -523,9 +574,10 @@ void Server::_signal_handler(const int signum) /** * @brief Adds signal handlers for the server. * - * This method sets up signal handlers for the server to catch specific signals, such as SIGINT - * (generated by pressing Ctrl+C) and SIGQUIT (generated by pressing Ctrl+\). When any of these - * signals are received, the corresponding signal handler function Server::_signal_handler is invoked. + * This method sets up signal handlers for the server to catch specific signals, + * such as SIGINT (generated by pressing Ctrl+C) and SIGQUIT (generated by + * pressing Ctrl+\). When any of these signals are received, the corresponding + * signal handler function Server::_signal_handler is invoked. */ void Server::_add_server_signal() @@ -535,43 +587,53 @@ void Server::_add_server_signal() } /* -** ------------------------------- VALIDATIONS FUCTIONS -------------------------------- +** ------------------------------- VALIDATIONS FUCTIONS +*-------------------------------- */ /** * @brief Checks if the port is valid. * - * This method verifies whether the provided port is valid by performing the following checks: + * This method verifies whether the provided port is valid by performing the + * following checks: * 1. Ensures that the port consists only of numeric characters. - * 2. Validates that the port number falls within the range of valid port numbers (1024 - 65535). + * 2. Validates that the port number falls within the range of valid port + * numbers (1024 - 65535). * * @param port The port to check represented as a string. - * @throws std::invalid_argument if the port is invalid (contains non-numeric characters or is out of range). + * @throws std::invalid_argument if the port is invalid (contains non-numeric + * characters or is out of range). */ -void Server::_is_valid_port(const std::string &port) +void Server::_is_valid_port(const std::string& port) { - if (!(port.find_first_not_of("0123456789") == std::string::npos && \ - std::atoi(port.c_str()) >= 1024 && std::atoi(port.c_str()) <= 65535)) + if (!(port.find_first_not_of("0123456789") == std::string::npos && + std::atoi(port.c_str()) >= 1024 && std::atoi(port.c_str()) <= 65535)) { - throw std::invalid_argument("Invalid port: either contains non-numeric characters or is out of range"); + throw std::invalid_argument( + "Invalid port: either contains non-numeric characters or is out of " + "range"); } } /** * @brief Checks if the nickname is valid. * - * This method verifies whether the provided nickname is valid by performing the following checks: + * This method verifies whether the provided nickname is valid by performing the + * following checks: * 1. Ensures that the nickname is at least 6 characters long. * 2. Validates that the nickname contains only alphanumeric characters. * * @param nickname The nickname to check. * @return true if the nickname is valid, false otherwise. */ -bool Server::_is_valid_nickname(const std::string &nickname) +bool Server::_is_valid_nickname(const std::string& nickname) { if (nickname.size() <= 3) return false; - for (std::string::const_iterator it = nickname.begin(); it != nickname.end(); ++it) { + for (std::string::const_iterator it = nickname.begin(); + it != nickname.end(); + ++it) + { if (!std::isalnum(*it)) return false; } @@ -581,17 +643,21 @@ bool Server::_is_valid_nickname(const std::string &nickname) /** * @brief Checks if the nickname is already in use. * - * This method checks if the provided nickname is already in use by another client. It iterates - * through the list of active clients and compares the provided nickname with the nicknames of - * other clients. If a match is found, the method returns true, indicating that the nickname is in use. + * This method checks if the provided nickname is already in use by another + * client. It iterates through the list of active clients and compares the + * provided nickname with the nicknames of other clients. If a match is found, + * the method returns true, indicating that the nickname is in use. * * @param fd The file descriptor associated with the client. * @param username The nickname to check. * @return true if the nickname is in use, false otherwise. */ -bool Server::_is_nickname_in_use(const int fd, const std::string &username) +bool Server::_is_nickname_in_use(const int fd, const std::string& username) { - for (std::vector::iterator it = _clients.begin(); it != _clients.end(); ++it) { + for (std::vector::iterator it = _clients.begin(); + it != _clients.end(); + ++it) + { if (it->get_nickname() == username && it->get_fd() != fd) return true; } @@ -599,7 +665,8 @@ bool Server::_is_nickname_in_use(const int fd, const std::string &username) } /* -** ------------------------------- CLIENT FUCTIONS -------------------------------- +** ------------------------------- CLIENT FUCTIONS +*-------------------------------- */ /** @@ -615,38 +682,43 @@ bool Server::_is_nickname_in_use(const int fd, const std::string &username) */ bool Server::_client_is_ready_to_login(const int fd) { - Client *client = _get_client(fd); + Client* client = _get_client(fd); - if (!client->get_username().empty() && !client->get_nickname().empty() && !client->get_is_logged()) + if (!client->get_username().empty() && !client->get_nickname().empty() && + !client->get_is_logged()) return true; return false; } /* -** ------------------------------- UTILS FUCTIONS -------------------------------- +** ------------------------------- UTILS FUCTIONS +*-------------------------------- */ /** * @brief Sends a response to the client. * - * This method sends a response to the client associated with the specified file descriptor. - * It sends the response message to the client socket using the send system call. + * This method sends a response to the client associated with the specified file + * descriptor. It sends the response message to the client socket using the send + * system call. * - * @param fd The file descriptor associated with the client to send the response. + * @param fd The file descriptor associated with the client to send the + * response. * @param response The response message to send to the client. */ -void Server::_send_response(const int fd, const std::string &response) +void Server::_send_response(const int fd, const std::string& response) { std::cout << "Response:\n" << response; - if(send(fd, response.c_str(), response.size(), 0) == -1) + if (send(fd, response.c_str(), response.size(), 0) == -1) std::cerr << "Response send() failed" << std::endl; } /** * @brief Converts a string to uppercase. * - * This method converts the provided string to uppercase by iterating through each character - * in the string and converting it to its uppercase equivalent using the std::toupper function. + * This method converts the provided string to uppercase by iterating through + * each character in the string and converting it to its uppercase equivalent + * using the std::toupper function. * * @param str The string to convert to uppercase. * @return The converted string in uppercase. @@ -654,14 +726,16 @@ void Server::_send_response(const int fd, const std::string &response) std::string Server::toupper(const std::string& str) { std::string result = str; - for (size_t i = 0; i < result.length(); ++i) { + for (size_t i = 0; i < result.length(); ++i) + { result[i] = std::toupper(result[i]); } return result; } /* -** ------------------------------- CHANNEL FUCTIONS -------------------------------- +** ------------------------------- CHANNEL FUCTIONS +*-------------------------------- */ /** @@ -674,13 +748,15 @@ std::string Server::toupper(const std::string& str) */ bool Server::_is_client_in_any_channel(const int fd) { - Client *client = this->_get_client(fd); - for (std::vector::iterator it = _channels.begin(); it != _channels.end(); ++it) - { - if ((*it)->has_client(client)) - { - return true; - } - } - return false; + Client* client = this->_get_client(fd); + for (std::vector::iterator it = _channels.begin(); + it != _channels.end(); + ++it) + { + if ((*it)->has_client(client)) + { + return true; + } + } + return false; } diff --git a/src/commands/Invite.cpp b/src/commands/Invite.cpp index a276d35..27d80de 100644 --- a/src/commands/Invite.cpp +++ b/src/commands/Invite.cpp @@ -10,15 +10,15 @@ /* */ /* ************************************************************************** */ -#include "Server.hpp" #include "Channel.hpp" +#include "Server.hpp" /* * Command: INVITE * Parameters: * Link: https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.7 * Example: INVITE Wiz #Twilight_Zone -*/ + */ /* * Cenários de Teste: @@ -26,92 +26,107 @@ * 2. O comando INVITE é recebido e o cliente não está registrado. * 3. O comando INVITE é recebido e o canal não existe. * 4. O comando INVITE é recebido e o cliente não está no canal. - * 5. O comando INVITE é recebido e o cliente não é operador do canal para convidar um cliente. + * 5. O comando INVITE é recebido e o cliente não é operador do canal para + * convidar um cliente. * 6. O comando INVITE é recebido e o cliente convidado não existe. * 7. O comando INVITE é recebido e o cliente convidado já está no canal. - * 8. O comando INVITE é recebido e o cliente convidado é convidado para o canal. + * 8. O comando INVITE é recebido e o cliente convidado é convidado para o + * canal. * 9. O comando INVITE é recebido e o cliente não está logado. * 10. O comando INVITE é recebido e o cliente está logado. - * -*/ + * + */ /** * @brief Handles the INVITE command received from the client. * - * This method processes the INVITE command received from the client and sends a response - * to the client indicating that the client has been invited to the channel. + * This method processes the INVITE command received from the client and sends a + * response to the client indicating that the client has been invited to the + * channel. * * @param buffer The buffer containing the INVITE command parameters. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_invite(const std::string &buffer, const int fd) +void Server::_handler_client_invite(const std::string& buffer, const int fd) { - // Obtém o cliente associado ao descritor de arquivo (fd) - Client* client = _get_client(fd); + // Obtém o cliente associado ao descritor de arquivo (fd) + Client* client = _get_client(fd); - // Verifica se o cliente está registrado e autenticado - if (!client->get_is_logged()) { - _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); - _reply_code = 451; - return; - } + // Verifica se o cliente está registrado e autenticado + if (!client->get_is_logged()) + { + _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); + _reply_code = 451; + return; + } - // Divide o buffer em parâmetros - std::vector params = _split_buffer(buffer, " "); - if (params.size() < 2) { - _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); - _reply_code = 461; - return; - } + // Divide o buffer em parâmetros + std::vector params = _split_buffer(buffer, " "); + if (params.size() < 2) + { + _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); + _reply_code = 461; + return; + } - // Extrai o apelido do cliente convidado e o nome do canal - std::string target_nickname = params[0]; - std::string target_channel = params[1]; + // Extrai o apelido do cliente convidado e o nome do canal + std::string target_nickname = params[0]; + std::string target_channel = params[1]; - // Verifica se o canal existe - Channel *channel = _get_channel(target_channel); - if (!channel) { - _send_response(fd, ERR_NOSUCHCHANNEL(target_channel)); - _reply_code = 403; - return; - } + // Verifica se o canal existe + Channel* channel = _get_channel(target_channel); + if (!channel) + { + _send_response(fd, ERR_NOSUCHCHANNEL(target_channel)); + _reply_code = 403; + return; + } - // Verifica se o cliente está no canal - if (!channel->has_client(client)) { - _send_response(fd, ERR_NOTONCHANNEL(target_channel)); - _reply_code = 442; - return; - } + // Verifica se o cliente está no canal + if (!channel->has_client(client)) + { + _send_response(fd, ERR_NOTONCHANNEL(target_channel)); + _reply_code = 442; + return; + } - // Verifica se o cliente é um operador do canal - if (!channel->is_channel_operator(client->get_nickname())) { - _send_response(fd, ERR_NOPRIVILEGES(client->get_nickname())); - _reply_code = 481; - return; - } + // Verifica se o cliente é um operador do canal + if (!channel->is_channel_operator(client->get_nickname())) + { + _send_response(fd, ERR_NOPRIVILEGES(client->get_nickname())); + _reply_code = 481; + return; + } - // Verifica se o cliente convidado existe - Client *invited_client = _get_client(target_nickname); - if (!invited_client) { - _send_response(fd, ERR_NOSUCHNICK(target_channel, target_nickname)); - _reply_code = 401; - return; - } + // Verifica se o cliente convidado existe + Client* invited_client = _get_client(target_nickname); + if (!invited_client) + { + _send_response(fd, ERR_NOSUCHNICK(target_channel, target_nickname)); + _reply_code = 401; + return; + } - // Verifica se o cliente convidado já está no canal - if (channel->has_client(invited_client)) { - _send_response(fd, ERR_USERONCHANNEL(target_nickname, target_channel)); - _reply_code = 443; - return; - } + // Verifica se o cliente convidado já está no canal + if (channel->has_client(invited_client)) + { + _send_response(fd, ERR_USERONCHANNEL(target_nickname, target_channel)); + _reply_code = 443; + return; + } - // Envia o convite ao cliente convidado - invited_client->add_channel_invited(target_channel); + // Envia o convite ao cliente convidado + invited_client->add_channel_invited(target_channel); - // Envia a resposta de convite ao cliente que enviou o convite - _send_response(fd, RPL_INVITING(client->get_hostname(), target_channel, client->get_nickname(), target_nickname)); - _reply_code = 200; + // Envia a resposta de convite ao cliente que enviou o convite + _send_response(fd, + RPL_INVITING(client->get_hostname(), + target_channel, + client->get_nickname(), + target_nickname)); + _reply_code = 200; - // Registra o comando INVITE recebido - std::cout << "INVITE command received from client " << buffer << std::endl; + // Registra o comando INVITE recebido + std::cout << "INVITE command received from client " << buffer << std::endl; } diff --git a/src/commands/Join.cpp b/src/commands/Join.cpp index f684e97..67f720b 100644 --- a/src/commands/Join.cpp +++ b/src/commands/Join.cpp @@ -16,7 +16,7 @@ * Command: JOIN * Parameters: {,} [{,}] * Link: https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.1 -*/ + */ /* * Cenários de Teste: @@ -31,87 +31,101 @@ * 9. O comando JOIN é recebido e o cliente não está logado. * 10. O comando JOIN é recebido e o cliente está logado. * -*/ + */ /** * @brief Handles the JOIN command received from the client. * - * This method processes the JOIN command received from the client and sends a response - * to the client indicating that the client has joined the channel. + * This method processes the JOIN command received from the client and sends a + * response to the client indicating that the client has joined the channel. * * @param buffer The buffer containing the JOIN command parameters. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_join(const std::string &buffer, const int fd) +void Server::_handler_client_join(const std::string& buffer, const int fd) { - Client* client = _get_client(fd); + Client* client = _get_client(fd); - // Verificar se o cliente está logado (descomentado caso seja necessário) - if (!client->get_is_logged()) { - _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); - _reply_code = 451; - return; - } + // Verificar se o cliente está logado (descomentado caso seja necessário) + if (!client->get_is_logged()) + { + _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); + _reply_code = 451; + return; + } - // Separar os parâmetros do comando - std::vector params = _split_buffer(buffer, SPACE); - if (params.size() < 1) { - _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); - _reply_code = 461; - return; - } + // Separar os parâmetros do comando + std::vector params = _split_buffer(buffer, SPACE); + if (params.size() < 1) + { + _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); + _reply_code = 461; + return; + } - std::string joining_channel = params[0]; - std::string channel_key = (params.size() > 1) ? params[1] : ""; + std::string joining_channel = params[0]; + std::string channel_key = (params.size() > 1) ? params[1] : ""; - // Verificar se o nome do canal é válido - if (joining_channel[0] != '#') { - _send_response(fd, ERR_NOSUCHCHANNEL(joining_channel)); - _reply_code = 403; - return; - } + // Verificar se o nome do canal é válido + if (joining_channel[0] != '#') + { + _send_response(fd, ERR_NOSUCHCHANNEL(joining_channel)); + _reply_code = 403; + return; + } - Channel* channel = _get_channel(joining_channel); - if (!channel) { - channel = new Channel(joining_channel); - _add_channel(channel); - channel->join(client); - channel->set_channel_operator(client); - return; - } + Channel* channel = _get_channel(joining_channel); + if (!channel) + { + channel = new Channel(joining_channel); + _add_channel(channel); + channel->join(client); + channel->set_channel_operator(client); + return; + } - // Verificar se o cliente já está no canal - if (channel->has_client(client)) { - _send_response(fd, ERR_ALREADYREGISTERED(client->get_nickname())); - _reply_code = 462; - return; - } + // Verificar se o cliente já está no canal + if (channel->has_client(client)) + { + _send_response(fd, ERR_ALREADYREGISTERED(client->get_nickname())); + _reply_code = 462; + return; + } - // Verificar se o canal está cheio - if (channel->is_channel_full()) { - _send_response(fd, ERR_CHANNELISFULL(client->get_nickname(), joining_channel)); - _reply_code = 422; - return; - } + // Verificar se o canal está cheio + if (channel->is_channel_full()) + { + _send_response( + fd, ERR_CHANNELISFULL(client->get_nickname(), joining_channel)); + _reply_code = 422; + return; + } - // Verificar se o canal é apenas para convidados - if (channel->is_channel_invite_only() && !client->is_channel_invited(joining_channel)) { - _send_response(fd, ERR_INVITEONLYCHAN(client->get_nickname(), joining_channel)); - _reply_code = 473; - return; - } + // Verificar se o canal é apenas para convidados + if (channel->is_channel_invite_only() && + !client->is_channel_invited(joining_channel)) + { + _send_response( + fd, ERR_INVITEONLYCHAN(client->get_nickname(), joining_channel)); + _reply_code = 473; + return; + } - // Verificar se o canal tem uma chave (senha) e se a chave fornecida é válida - if (channel->has_key() && channel_key != channel->get_channel_key()) { - _send_response(fd, ERR_BADCHANNELKEY(client->get_nickname(), joining_channel)); - _reply_code = 475; - return; - } + // Verificar se o canal tem uma chave (senha) e se a chave fornecida é + // válida + if (channel->has_key() && channel_key != channel->get_channel_key()) + { + _send_response( + fd, ERR_BADCHANNELKEY(client->get_nickname(), joining_channel)); + _reply_code = 475; + return; + } - // Adicionar o cliente ao canal - channel->join(client); - _reply_code = 200; + // Adicionar o cliente ao canal + channel->join(client); + _reply_code = 200; - // Registra o comando JOIN recebido - std::cout << "JOIN command received from client " << buffer << std::endl; + // Registra o comando JOIN recebido + std::cout << "JOIN command received from client " << buffer << std::endl; } \ No newline at end of file diff --git a/src/commands/Kick.cpp b/src/commands/Kick.cpp index b074e77..8ec5ec8 100644 --- a/src/commands/Kick.cpp +++ b/src/commands/Kick.cpp @@ -13,10 +13,10 @@ #include "Server.hpp" /* - * Command: Kick + * Command: Kick * Parameters: [] * Reference: https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.8 -*/ + */ /* * Cenários de Teste: @@ -27,89 +27,112 @@ * 5. O comando KICK é recebido e o cliente alvo não existe. * 6. O comando KICK é recebido e o cliente alvo não está no canal. * 7. O comando KICK é recebido e o cliente é expulso do canal com sucesso. - * 8. O comando KICK é recebido e o cliente é expulso do canal com sucesso e um comentário é enviado. - * -*/ + * 8. O comando KICK é recebido e o cliente é expulso do canal com sucesso e um + * comentário é enviado. + * + */ /** * @brief Handles the KICK command received from the client. * - * This method processes the KICK command received from the client and sends a response - * to the client indicating that the client has been kicked from the channel. + * This method processes the KICK command received from the client and sends a + * response to the client indicating that the client has been kicked from the + * channel. * * @param buffer The buffer containing the KICK command parameters. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_kick(const std::string &buffer, const int fd) +void Server::_handler_client_kick(const std::string& buffer, const int fd) { Client* client = _get_client(fd); - if (!client->get_is_logged()) { - _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); - _reply_code = 451; - return; - } + if (!client->get_is_logged()) + { + _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); + _reply_code = 451; + return; + } - // Divide o buffer em parâmetros e verifica se há parâmetros suficientes - std::vector params = _split_buffer(buffer, SPACE); - if (params.size() < 2) { - _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); - _reply_code = 461; - return; - } + // Divide o buffer em parâmetros e verifica se há parâmetros suficientes + std::vector params = _split_buffer(buffer, SPACE); + if (params.size() < 2) + { + _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); + _reply_code = 461; + return; + } - // Extrai o nome do canal e o apelido do cliente a ser expulso - std::string channel_name = params[0]; - std::vector comments = _split_buffer(params[1], SPACE); - std::string target_nickname = comments[0]; + // Extrai o nome do canal e o apelido do cliente a ser expulso + std::string channel_name = params[0]; + std::vector comments = _split_buffer(params[1], SPACE); + std::string target_nickname = comments[0]; - // Verifica se o canal existe - Channel *channel = _get_channel(channel_name); - if (!channel) { - _send_response(fd, ERR_NOSUCHCHANNEL(channel_name)); - _reply_code = 403; - return; - } + // Verifica se o canal existe + Channel* channel = _get_channel(channel_name); + if (!channel) + { + _send_response(fd, ERR_NOSUCHCHANNEL(channel_name)); + _reply_code = 403; + return; + } - // Verifica se o cliente está no canal - if (!channel->has_client(client)) { - _send_response(fd, ERR_NOTONCHANNEL(channel_name)); - _reply_code = 442; - return; - } + // Verifica se o cliente está no canal + if (!channel->has_client(client)) + { + _send_response(fd, ERR_NOTONCHANNEL(channel_name)); + _reply_code = 442; + return; + } - // Verifica se o cliente é um operador do canal - if (!channel->is_channel_operator(client->get_nickname())) { - _send_response(fd, ERR_CHANOPRIVSNEEDED(channel_name)); - _reply_code = 482; - return; - } + // Verifica se o cliente é um operador do canal + if (!channel->is_channel_operator(client->get_nickname())) + { + _send_response(fd, ERR_CHANOPRIVSNEEDED(channel_name)); + _reply_code = 482; + return; + } - // Verifica se o cliente alvo existe - Client *target_client = _get_client(target_nickname); - if (!target_client) { - _send_response(fd, ERR_NOSUCHNICK(channel_name, target_nickname)); - _reply_code = 401; - return; - } + // Verifica se o cliente alvo existe + Client* target_client = _get_client(target_nickname); + if (!target_client) + { + _send_response(fd, ERR_NOSUCHNICK(channel_name, target_nickname)); + _reply_code = 401; + return; + } - // Verifica se o cliente alvo está no canal - if (!channel->has_client(target_client)) { - _send_response(fd, ERR_USERNOTINCHANNEL(target_nickname, channel_name)); - _reply_code = 441; - return; - } + // Verifica se o cliente alvo está no canal + if (!channel->has_client(target_client)) + { + _send_response(fd, ERR_USERNOTINCHANNEL(target_nickname, channel_name)); + _reply_code = 441; + return; + } // Check if option parameter exists - if (params.size() > 2) { - _send_response(fd, RPL_KICK(client->get_hostname(), channel_name, client->get_nickname(), target_client->get_nickname(), comments[1])); - } else { - _send_response(fd, RPL_KICK(client->get_hostname(), channel_name, client->get_nickname(), target_client->get_nickname(), "")); + if (params.size() > 2) + { + _send_response(fd, + RPL_KICK(client->get_hostname(), + channel_name, + client->get_nickname(), + target_client->get_nickname(), + comments[1])); + } + else + { + _send_response(fd, + RPL_KICK(client->get_hostname(), + channel_name, + client->get_nickname(), + target_client->get_nickname(), + "")); } channel->kick(target_client); _reply_code = 200; - // Registra o comando KICK recebido - std::cout << "KICK command received from client " << buffer << std::endl; + // Registra o comando KICK recebido + std::cout << "KICK command received from client " << buffer << std::endl; } diff --git a/src/commands/Mode.cpp b/src/commands/Mode.cpp index b3ae584..45b2942 100644 --- a/src/commands/Mode.cpp +++ b/src/commands/Mode.cpp @@ -18,162 +18,215 @@ * Command: MODE * Parameters: {[+|-]|o|p|s|i|t|n|b|v} [] [] * Reference: https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.3 -*/ + */ /* * Cenários de Teste: * 1. O comando MODE é recebido sem parâmetros suficientes. * 2. O comando MODE é recebido e o canal não existe. - * 3. O comando MODE é recebido e o cliente não tem privilégios de operador no canal. - * 4. O comando MODE é recebido e o cliente tem privilégios de operador no canal. + * 3. O comando MODE é recebido e o cliente não tem privilégios de operador no + * canal. + * 4. O comando MODE é recebido e o cliente tem privilégios de operador no + * canal. * 5. O comando MODE é recebido e o modo do canal é alterado com sucesso. * -*/ + */ /** * @brief Handles the MODE command received from the client. * - * This method processes the MODE command received from the client and sends a response - * to the client indicating the channel modes supported by the server. + * This method processes the MODE command received from the client and sends a + * response to the client indicating the channel modes supported by the server. * * @param buffer The buffer containing the MODE command parameters. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_mode(const std::string &buffer, const int fd) { - // Registra o comando MODE recebido - std::cout << "MODE command received: " << buffer << std::endl; - - // Separar os argumentos do comando - std::istringstream iss(buffer); - std::string chnl, modes, arg; - - // Verificar e extrair os parâmetros de acordo com o padrão esperado - iss >> chnl >> modes; - if (!chnl.empty() && !modes.empty()) { - iss >> arg; - } - - Client* admin = _get_client(fd); - Channel* channel = _get_channel(chnl); - - // Verificar se todos os parâmetros obrigatórios foram fornecidos - if (chnl.empty() || modes.empty()) { - _send_response(fd, ERR_NEEDMOREPARAMS(admin->get_nickname())); - _reply_code = 461; - return; - } - - // Verificar se o canal existe - if (!channel) { - _send_response(fd, ERR_NOSUCHCHANNEL(chnl)); - _reply_code = 403; - return; - } - - // Verificar se o cliente tem privilégios de operador no canal - if (!channel->is_channel_operator(admin->get_nickname())) { - _send_response(fd, ERR_CHANOPRIVSNEEDED(chnl)); - _reply_code = 482; - return; - } - - // Tratar o comando MODE - if (!_parse_mode_command(modes, channel, _get_client(arg), arg, fd)) { - _send_response(fd, ERR_INVALIDMODEPARM(admin->get_nickname(), modes[1])); - _reply_code = 696; - return; - } +void Server::_handler_client_mode(const std::string& buffer, const int fd) +{ + // Registra o comando MODE recebido + std::cout << "MODE command received: " << buffer << std::endl; + + // Separar os argumentos do comando + std::istringstream iss(buffer); + std::string chnl, modes, arg; + + // Verificar e extrair os parâmetros de acordo com o padrão esperado + iss >> chnl >> modes; + if (!chnl.empty() && !modes.empty()) + { + iss >> arg; + } + + Client* admin = _get_client(fd); + Channel* channel = _get_channel(chnl); + + // Verificar se todos os parâmetros obrigatórios foram fornecidos + if (chnl.empty() || modes.empty()) + { + _send_response(fd, ERR_NEEDMOREPARAMS(admin->get_nickname())); + _reply_code = 461; + return; + } + + // Verificar se o canal existe + if (!channel) + { + _send_response(fd, ERR_NOSUCHCHANNEL(chnl)); + _reply_code = 403; + return; + } + + // Verificar se o cliente tem privilégios de operador no canal + if (!channel->is_channel_operator(admin->get_nickname())) + { + _send_response(fd, ERR_CHANOPRIVSNEEDED(chnl)); + _reply_code = 482; + return; + } + + // Tratar o comando MODE + if (!_parse_mode_command(modes, channel, _get_client(arg), arg, fd)) + { + _send_response(fd, + ERR_INVALIDMODEPARM(admin->get_nickname(), modes[1])); + _reply_code = 696; + return; + } } -bool Server::_parse_mode_command(const std::string &modes, Channel* channel, Client* client, const std::string &arg, const int fd) { - bool set = false; - char mode = 0; - - for (size_t i = 0; i < modes.size(); ++i) { - if (modes[i] == '+' || modes[i] == '-') { - set = (modes[i] == '+'); - } else { - mode = modes[i]; - - if (!_handler_mode_flags(channel, client, mode, set, arg, fd)) { - _send_response(fd, ERR_UNKNOWNMODE(client->get_nickname(), channel->get_name(), mode)); - _reply_code = 472; - return false; - } - } - } - return true; +bool Server::_parse_mode_command(const std::string& modes, Channel* channel, + Client* client, const std::string& arg, + const int fd) +{ + bool set = false; + char mode = 0; + + for (size_t i = 0; i < modes.size(); ++i) + { + if (modes[i] == '+' || modes[i] == '-') + { + set = (modes[i] == '+'); + } + else + { + mode = modes[i]; + + if (!_handler_mode_flags(channel, client, mode, set, arg, fd)) + { + _send_response( + fd, + ERR_UNKNOWNMODE( + client->get_nickname(), channel->get_name(), mode)); + _reply_code = 472; + return false; + } + } + } + return true; } -bool Server::_handler_mode_flags(Channel* channel, Client* client, char mode, bool set, const std::string &arg, const int fd) { - switch (mode) { - case 'i': - _handler_invite_only_mode(channel, set); - break; - case 't': - _handler_topic_restriction_mode(channel, set); - break; - case 'k': - _handle_password_mode(channel, arg, set); - break; - case 'o': - _handle_operator_privileges_mode(channel, client, set); - break; - case 'l': - _handle_limit_mode(channel, client, arg, set, fd); - break; - default: - return false; - } - return true; +bool Server::_handler_mode_flags(Channel* channel, Client* client, char mode, + bool set, const std::string& arg, const int fd) +{ + switch (mode) + { + case 'i': + _handler_invite_only_mode(channel, set); + break; + case 't': + _handler_topic_restriction_mode(channel, set); + break; + case 'k': + _handle_password_mode(channel, arg, set); + break; + case 'o': + _handle_operator_privileges_mode(channel, client, set); + break; + case 'l': + _handle_limit_mode(channel, client, arg, set, fd); + break; + default: + return false; + } + return true; } -void Server::_handler_invite_only_mode(Channel* channel, bool set) { - if (set) { - channel->set_invite_only(); - } else { - channel->remove_invite_only(); - } +void Server::_handler_invite_only_mode(Channel* channel, bool set) +{ + if (set) + { + channel->set_invite_only(); + } + else + { + channel->remove_invite_only(); + } } -void Server::_handler_topic_restriction_mode(Channel* channel, bool set) { - if (set) { - channel->set_topic_restriction(); - } else { - channel->remove_topic_restriction(); - } +void Server::_handler_topic_restriction_mode(Channel* channel, bool set) +{ + if (set) + { + channel->set_topic_restriction(); + } + else + { + channel->remove_topic_restriction(); + } } -void Server::_handle_password_mode(Channel* channel, const std::string &argument, bool set) { - if (set) { - channel->set_key(argument); - } else { - channel->remove_key(); - } +void Server::_handle_password_mode(Channel* channel, + const std::string& argument, bool set) +{ + if (set) + { + channel->set_key(argument); + } + else + { + channel->remove_key(); + } } -void Server::_handle_operator_privileges_mode(Channel* channel, Client* client, bool set) { - if (set) { - if (client) { - channel->set_channel_operator(client); - } - } else { - if (client) { - channel->remove_channel_operator(client); - } - } +void Server::_handle_operator_privileges_mode(Channel* channel, Client* client, + bool set) +{ + if (set) + { + if (client) + { + channel->set_channel_operator(client); + } + } + else + { + if (client) + { + channel->remove_channel_operator(client); + } + } } -void Server::_handle_limit_mode(Channel* channel, Client* client, const std::string &argument, bool set, const int fd) { - if (set) { - if (!argument.empty()) { - channel->set_limit(std::atoi(argument.c_str())); - } else { - // Respond with error if limit is not provided - _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); - _reply_code = 461; - } - } else { - channel->remove_limit(); - } +void Server::_handle_limit_mode(Channel* channel, Client* client, + const std::string& argument, bool set, + const int fd) +{ + if (set) + { + if (!argument.empty()) + { + channel->set_limit(std::atoi(argument.c_str())); + } + else + { + // Respond with error if limit is not provided + _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); + _reply_code = 461; + } + } + else + { + channel->remove_limit(); + } } \ No newline at end of file diff --git a/src/commands/Nick.cpp b/src/commands/Nick.cpp index cc7aeff..6a2d3b2 100644 --- a/src/commands/Nick.cpp +++ b/src/commands/Nick.cpp @@ -10,8 +10,8 @@ /* */ /* ************************************************************************** */ -#include "Server.hpp" #include "Replies.hpp" +#include "Server.hpp" #define NICK_CMD "NICK" @@ -19,42 +19,54 @@ * Command: NICK * Parameters: * Reference: https://datatracker.ietf.org/doc/html/rfc1459#section-4.1.2 -*/ + */ /** * @brief Handles the NICK command received from the client. * - * This method processes the NICK command received from the client and sends a response - * to the client indicating that the client's nickname has been changed. + * This method processes the NICK command received from the client and sends a + * response to the client indicating that the client's nickname has been + * changed. * * @param nickname The new nickname to be assigned to the client. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_nickname(const std::string &buffer, const int fd) +void Server::_handler_client_nickname(const std::string& buffer, const int fd) { // Registra o comando NICK recebido - std::cout << "NICK command received: " << buffer << std::endl; + std::cout << "NICK command received: " << buffer << std::endl; Client* client = _get_client(fd); - if (buffer.empty()) { + if (buffer.empty()) + { _send_response(fd, ERR_NEEDMOREPARAMS(std::string("*"))); _reply_code = 461; - } else if (!client->get_is_authenticated()) { + } + else if (!client->get_is_authenticated()) + { _send_response(fd, ERR_NOTREGISTERED(std::string("*"))); _reply_code = 451; - } else if (!_is_valid_nickname(buffer)) { + } + else if (!_is_valid_nickname(buffer)) + { //_send_response(fd, ERR_ERRONEUSNICK(client->get_nickname())); _reply_code = 432; - } else if (_is_nickname_in_use(fd, buffer)) { + } + else if (_is_nickname_in_use(fd, buffer)) + { _send_response(fd, ERR_NICKINUSE(client->get_nickname())); _reply_code = 433; - } else { + } + else + { client->set_nickname(buffer); - if (_client_is_ready_to_login(fd)) { + if (_client_is_ready_to_login(fd)) + { client->set_is_logged(fd); _send_response(fd, RPL_CONNECTED(client->get_nickname())); - _reply_code = 001; + _reply_code = 001; return; } _reply_code = 200; diff --git a/src/commands/Part.cpp b/src/commands/Part.cpp index 66c3e03..3b08778 100644 --- a/src/commands/Part.cpp +++ b/src/commands/Part.cpp @@ -16,69 +16,77 @@ * Command: PART * Parameters: {,} * Link: https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.2 -*/ + */ /* * Test Cases: * 1. The PART command is received without enough parameters. * 2. The PART command is received and the channel does not exist. * 3. The PART command is received and the client is not in the channel. - * 4. The PART command is received and the client leaves the channel successfully. -*/ + * 4. The PART command is received and the client leaves the channel + * successfully. + */ /** * @brief Handles the PART command received from the client. * - * This method processes the PART command received from the client and sends a response - * to the client indicating that the client has left the channel. + * This method processes the PART command received from the client and sends a + * response to the client indicating that the client has left the channel. * * @param buffer The buffer containing the PART command parameters. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_part(const std::string &buffer, const int fd) +void Server::_handler_client_part(const std::string& buffer, const int fd) { - // Obtém o cliente associado ao descritor de arquivo (fd) - Client* client = _get_client(fd); + // Obtém o cliente associado ao descritor de arquivo (fd) + Client* client = _get_client(fd); - // Verifica se o cliente está registrado e autenticado - if (!client->get_is_logged()) { - _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); - _reply_code = 451; - return; - } + // Verifica se o cliente está registrado e autenticado + if (!client->get_is_logged()) + { + _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); + _reply_code = 451; + return; + } - // Divide o buffer em parâmetros - std::vector params = _split_buffer(buffer, SPACE); - if (params.size() < 1) { - _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); - _reply_code = 461; - return; - } + // Divide o buffer em parâmetros + std::vector params = _split_buffer(buffer, SPACE); + if (params.size() < 1) + { + _send_response(fd, ERR_NEEDMOREPARAMS(client->get_nickname())); + _reply_code = 461; + return; + } - // Extrai o nome do canal a ser deixado - std::string channel_name = params[0]; + // Extrai o nome do canal a ser deixado + std::string channel_name = params[0]; - Channel *channel = _get_channel(channel_name); - if (!channel) { - _send_response(fd, ERR_NOSUCHCHANNEL(channel_name)); - _reply_code = 403; - return; - } + Channel* channel = _get_channel(channel_name); + if (!channel) + { + _send_response(fd, ERR_NOSUCHCHANNEL(channel_name)); + _reply_code = 403; + return; + } - // Verifica se o cliente está no canal - if (!channel->has_client(client)) { - _send_response(fd, ERR_NOTONCHANNEL(channel_name)); - _reply_code = 442; - return; - } + // Verifica se o cliente está no canal + if (!channel->has_client(client)) + { + _send_response(fd, ERR_NOTONCHANNEL(channel_name)); + _reply_code = 442; + return; + } - // Remove o cliente do canal - channel->part(client); + // Remove o cliente do canal + channel->part(client); - // Envia uma resposta ao cliente - _send_response(fd, RPL_PART(client->get_hostname(), channel_name, client->get_nickname())); - _reply_code = 200; + // Envia uma resposta ao cliente + _send_response( + fd, + RPL_PART(client->get_hostname(), channel_name, client->get_nickname())); + _reply_code = 200; - // Registra o comando PART recebido - std::cout << "PART command received from client " << buffer << std::endl; + // Registra o comando PART recebido + std::cout << "PART command received from client " << buffer << std::endl; } diff --git a/src/commands/Pass.cpp b/src/commands/Pass.cpp index 81252e9..32ab20d 100644 --- a/src/commands/Pass.cpp +++ b/src/commands/Pass.cpp @@ -16,7 +16,7 @@ * Command: PASS * Parameters: * Reference: https://datatracker.ietf.org/doc/html/rfc1459#section-4.1.1 -*/ + */ /* * Cenários de Teste: @@ -28,35 +28,43 @@ * 6. O comando PASS é recebido e o cliente está logado. * 7. O comando PASS é recebido e o cliente não está autenticado. * 8. O comando PASS é recebido e o cliente está autenticado. - * -*/ + * + */ /** * @brief Handles the PASSWORD command received from the client. * - * This method processes the PASSWORD command received from the client and sends a response - * to the client indicating that the client's password has been set. + * This method processes the PASSWORD command received from the client and sends + * a response to the client indicating that the client's password has been set. * * @param password The password to be assigned to the client. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_password(const std::string &buffer, const int fd) +void Server::_handler_client_password(const std::string& buffer, const int fd) { // Registra o comando PASS recebido - std::cout << "PASS command received: " << buffer << std::endl; - + std::cout << "PASS command received: " << buffer << std::endl; + Client* client = _get_client(fd); - - if (buffer.empty()) { + + if (buffer.empty()) + { _send_response(fd, ERR_NEEDMOREPARAMS(std::string("*"))); _reply_code = 461; - } else if (client->get_is_authenticated()) { + } + else if (client->get_is_authenticated()) + { _send_response(fd, ERR_ALREADYREGISTERED(std::string("*"))); _reply_code = 462; - } else if (_password != buffer) { + } + else if (_password != buffer) + { _send_response(fd, ERR_INCORPASS(std::string("*"))); _reply_code = 464; - } else { + } + else + { client->set_is_authenticated(true); _reply_code = 200; } diff --git a/src/commands/Privmsg.cpp b/src/commands/Privmsg.cpp index aa0689f..a509040 100644 --- a/src/commands/Privmsg.cpp +++ b/src/commands/Privmsg.cpp @@ -10,55 +10,59 @@ /* */ /* ************************************************************************** */ -#include "Server.hpp" #include "Channel.hpp" #include "Client.hpp" +#include "Server.hpp" /* * Command: PRIVMSG * Parameters: {,} * Link: https://datatracker.ietf.org/doc/html/rfc1459#section-4.4.1 -*/ + */ -#include -#include #include +#include #include - +#include /** * @brief Splits a string into tokens based on a delimiter. * - * This function takes a string and a delimiter as input and splits the string into tokens based on the delimiter. - * The tokens are stored in a vector and returned. + * This function takes a string and a delimiter as input and splits the string + * into tokens based on the delimiter. The tokens are stored in a vector and + * returned. * * @param s The string to be split. * @param delimiter The delimiter used to split the string. * @return A vector of strings containing the tokens. */ -std::vector split_parameters(const std::string &s, const std::string &delimiter) { - std::vector tokens; - size_t start = 0; - size_t end = s.find(delimiter); - while (end != std::string::npos) { - tokens.push_back(s.substr(start, end - start)); - start = end + delimiter.length(); - end = s.find(delimiter, start); - } - tokens.push_back(s.substr(start, end)); - return tokens; +std::vector split_parameters(const std::string& s, + const std::string& delimiter) +{ + std::vector tokens; + size_t start = 0; + size_t end = s.find(delimiter); + while (end != std::string::npos) + { + tokens.push_back(s.substr(start, end - start)); + start = end + delimiter.length(); + end = s.find(delimiter, start); + } + tokens.push_back(s.substr(start, end)); + return tokens; } /** * @brief Handles the PRIVMSG command received from the client. * - * This method processes the PRIVMSG command received from the client and sends a response - * to the client indicating that the message has been sent. + * This method processes the PRIVMSG command received from the client and sends + * a response to the client indicating that the message has been sent. * * @param buffer The buffer containing the PRIVMSG command parameters. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_privmsg(const std::string &buffer, const int fd) +void Server::_handler_client_privmsg(const std::string& buffer, const int fd) { Client* client = _get_client(fd); @@ -76,19 +80,21 @@ void Server::_handler_client_privmsg(const std::string &buffer, const int fd) _reply_code = 461; return; } - + std::vector receivers = split_parameters(params[0], ","); std::cout << receivers[0] << std::endl; - + // Validate channel and client inputs. Otherwise, return an error - for (std::vector::iterator it = receivers.begin(); it != receivers.end(); ++it) + for (std::vector::iterator it = receivers.begin(); + it != receivers.end(); + ++it) { // Check if first character is # if ((*it)[0] == '#') { // Check if the channel exists - Channel *target_channel = this->_get_channel(*it); + Channel* target_channel = this->_get_channel(*it); if (!target_channel) { _send_response(fd, ERR_NOSUCHCHANNEL(*it)); @@ -99,7 +105,8 @@ void Server::_handler_client_privmsg(const std::string &buffer, const int fd) // Check if the client is in the channel if (!target_channel->has_client(client)) { - _send_response(fd, ERR_NOTONCHANNEL(client->get_nickname())); + _send_response(fd, + ERR_NOTONCHANNEL(client->get_nickname())); _reply_code = 442; return; } @@ -107,36 +114,47 @@ void Server::_handler_client_privmsg(const std::string &buffer, const int fd) else { // Check if the receiver exists - Client *target_client = this->_get_client(*it); + Client* target_client = this->_get_client(*it); if (!target_client) { - _send_response(fd, ERR_NOSUCHNICK(std::string(""), client->get_nickname())); + _send_response(fd, + ERR_NOSUCHNICK(std::string(""), + client->get_nickname())); _reply_code = 401; return; } } } - // Both channels and clients exist, now it's time to send the private message - for (std::vector::iterator it = receivers.begin(); it != receivers.end(); ++it) + // Both channels and clients exist, now it's time to send the private + // message + for (std::vector::iterator it = receivers.begin(); + it != receivers.end(); + ++it) { if ((*it)[0] == '#') { - Channel *target_channel = this->_get_channel(*it); - - std::cout << "1) THIS IS CHANNEL TARGET:" << target_channel->get_name() << std::endl; - - target_channel->broadcast(client, target_channel->get_name(), params[1]); - - //_send_response(fd, RPL_PRIVMSG(client->get_hostname(), target_channel->get_name(), params[1])); + Channel* target_channel = this->_get_channel(*it); + + std::cout << "1) THIS IS CHANNEL TARGET:" + << target_channel->get_name() << std::endl; + + target_channel->broadcast( + client, target_channel->get_name(), params[1]); + + //_send_response(fd, RPL_PRIVMSG(client->get_hostname(), + //target_channel->get_name(), params[1])); } else { // Check if the receiver exists - Client *target_client = this->_get_client(*it); + Client* target_client = this->_get_client(*it); // Send the message to the receiver - _send_response(target_client->get_fd(), RPL_PRIVMSG(client->get_hostname(), target_client->get_nickname(), params[1])); + _send_response(target_client->get_fd(), + RPL_PRIVMSG(client->get_hostname(), + target_client->get_nickname(), + params[1])); } } } @@ -145,5 +163,6 @@ void Server::_handler_client_privmsg(const std::string &buffer, const int fd) _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); _reply_code = 451; } - //_send_response(fd, RPL_PRIVMSG(client->get_hostname(), "ft_transcendence", "Hello, Carlos!")); + //_send_response(fd, RPL_PRIVMSG(client->get_hostname(), "ft_transcendence", + //"Hello, Carlos!")); } \ No newline at end of file diff --git a/src/commands/Quit.cpp b/src/commands/Quit.cpp index 399e356..f87c2f6 100644 --- a/src/commands/Quit.cpp +++ b/src/commands/Quit.cpp @@ -10,46 +10,50 @@ /* */ /* ************************************************************************** */ -#include "Server.hpp" #include +#include "Server.hpp" /* * Command: QUIT * Parameters: [] * Link: https://datatracker.ietf.org/doc/html/rfc1459#section-4.1.6 -*/ + */ /** * @brief Handles the QUIT command received from the client. * - * This method processes the QUIT command received from the client and sends a response - * to the client indicating that the client has quit the server. + * This method processes the QUIT command received from the client and sends a + * response to the client indicating that the client has quit the server. + * + * To avoid memory leak, if the client being disconnected is the last one in a + * channel, the channel is deleted. * - * To avoid memory leak, if the client being disconnected is the last one in a channel, - * the channel is deleted. - * * @param buffer The buffer containing the QUIT command parameters. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_quit(const std::string &/* buffer */, const int fd) +void Server::_handler_client_quit(const std::string& /* buffer */, const int fd) { - Client* client = _get_client(fd); + Client* client = _get_client(fd); - for (std::vector::iterator it = _channels.begin(); it != _channels.end(); ++it) - { - Channel *channel = *it; - if (channel->has_client(client)) + for (std::vector::iterator it = _channels.begin(); + it != _channels.end(); + ++it) + { + Channel* channel = *it; + if (channel->has_client(client)) { - channel->part(client); - if (channel->get_channel_clients().size() == 0) + channel->part(client); + if (channel->get_channel_clients().size() == 0) delete channel; } - } + } - _send_response(fd, RPL_QUITMESSAGE(client->get_nickname())); + _send_response(fd, RPL_QUITMESSAGE(client->get_nickname())); _reply_code = 301; - std::cout << RED << "Client <" << fd << "> Disconnected" << WHI << std::endl; + std::cout << RED << "Client <" << fd << "> Disconnected" << WHI + << std::endl; _clear_client(fd); close(fd); } diff --git a/src/commands/Topic.cpp b/src/commands/Topic.cpp index 3db5af5..6e51ad2 100644 --- a/src/commands/Topic.cpp +++ b/src/commands/Topic.cpp @@ -16,58 +16,79 @@ * Command: TOPIC * Parameters: [] * Reference: https://datatracker.ietf.org/doc/html/rfc1459#section-4.2.4 -*/ + */ /** * @brief Handles the TOPIC command received from the client. * - * This method processes the TOPIC command received from the client and sends a response - * to the client indicating the topic of the channel. + * This method processes the TOPIC command received from the client and sends a + * response to the client indicating the topic of the channel. * * @param buffer The buffer containing the TOPIC command parameters. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_topic(const std::string &buffer, const int fd) +void Server::_handler_client_topic(const std::string& buffer, const int fd) { // Registra o comando TOPIC recebido - std::cout << "TOPIC command received: " << buffer << std::endl; - + std::cout << "TOPIC command received: " << buffer << std::endl; + std::istringstream iss(buffer); std::string chnl, topic; iss >> chnl >> topic; - if (!chnl.empty()) { + if (!chnl.empty()) + { iss >> topic; } Client* client = _get_client(fd); Channel* channel = _get_channel(chnl); - if (!client->get_is_logged()) { + if (!client->get_is_logged()) + { _send_response(fd, ERR_NOTREGISTERED(client->get_nickname())); _reply_code = 451; - } else if (!channel) { - _send_response(fd, ERR_NOSUCHCHANNEL(chnl)); + } + else if (!channel) + { + _send_response(fd, ERR_NOSUCHCHANNEL(chnl)); _reply_code = 403; - } else if (!channel->is_client_in_channel(client->get_nickname())) { - _send_response(fd, ERR_NOTONCHANNEL(client->get_nickname())); + } + else if (!channel->is_client_in_channel(client->get_nickname())) + { + _send_response(fd, ERR_NOTONCHANNEL(client->get_nickname())); _reply_code = 442; - } else if (topic.empty()) { - if (channel->get_topic().empty()) { - _send_response(fd, RPL_NOTOPIC(client->get_nickname(), channel->get_name())); + } + else if (topic.empty()) + { + if (channel->get_topic().empty()) + { + _send_response( + fd, RPL_NOTOPIC(client->get_nickname(), channel->get_name())); _reply_code = 331; - } else { - _send_response(fd, RPL_TOPIC(client->get_nickname(), channel->get_name(), channel->get_topic())); + } + else + { + _send_response(fd, + RPL_TOPIC(client->get_nickname(), + channel->get_name(), + channel->get_topic())); _reply_code = 332; } - } else { - if (!channel->is_channel_operator(client->get_nickname()) - || channel->get_topic_restriction()) { + } + else + { + if (!channel->is_channel_operator(client->get_nickname()) || + channel->get_topic_restriction()) + { _send_response(fd, ERR_CHANOPRIVSNEEDED(channel->get_name())); _reply_code = 482; - } else { + } + else + { channel->set_topic(topic); - _send_response(fd, RPL_TOPIC(client->get_nickname(), chnl, topic)); + _send_response(fd, RPL_TOPIC(client->get_nickname(), chnl, topic)); _reply_code = 332; } } diff --git a/src/commands/User.cpp b/src/commands/User.cpp index 30c643b..576c7a4 100644 --- a/src/commands/User.cpp +++ b/src/commands/User.cpp @@ -16,7 +16,7 @@ * Command: USER * Parameters: * Link: https://datatracker.ietf.org/doc/html/rfc1459#section-4.1.3 -*/ + */ /* * Cenários de Teste: @@ -28,42 +28,53 @@ * 6. O comando USER é recebido e o cliente já está logado. * 7. O comando USER é recebido e o cliente não está autenticado. * 8. O comando USER é recebido e o cliente está autenticado. - * -*/ + * + */ /** * @brief Handles the USERNAME command received from the client. * - * This method processes the USERNAME command received from the client and sends a response - * to the client indicating that the client's username has been set. + * This method processes the USERNAME command received from the client and sends + * a response to the client indicating that the client's username has been set. * * @param username The username to be assigned to the client. - * @param fd The file descriptor associated with the client that sent the command. + * @param fd The file descriptor associated with the client that sent the + * command. */ -void Server::_handler_client_username(const std::string &buffer, const int fd) +void Server::_handler_client_username(const std::string& buffer, const int fd) { - // Registra o comando USER recebido - std::cout << "USER command received: " << buffer << std::endl; - - Client* client = _get_client(fd); - - if (buffer.empty()) { - _send_response(fd, ERR_NEEDMOREPARAMS(std::string("*"))); - _reply_code = 461; - } else if (!client || !client->get_is_authenticated()) { - _send_response(fd, ERR_NOTREGISTERED(std::string("*"))); - _reply_code = 451; - } else if (!client->get_username().empty()) { - _send_response(fd, ERR_ALREADYREGISTERED(client->get_nickname())); - _reply_code = 462; - } else { - client->set_username(buffer); - if (_client_is_ready_to_login(fd)) { - client->set_is_logged(fd); - _send_response(fd, RPL_CONNECTED(client->get_nickname())); - _reply_code = 001; - } else { - _reply_code = 200; - } - } + // Registra o comando USER recebido + std::cout << "USER command received: " << buffer << std::endl; + + Client* client = _get_client(fd); + + if (buffer.empty()) + { + _send_response(fd, ERR_NEEDMOREPARAMS(std::string("*"))); + _reply_code = 461; + } + else if (!client || !client->get_is_authenticated()) + { + _send_response(fd, ERR_NOTREGISTERED(std::string("*"))); + _reply_code = 451; + } + else if (!client->get_username().empty()) + { + _send_response(fd, ERR_ALREADYREGISTERED(client->get_nickname())); + _reply_code = 462; + } + else + { + client->set_username(buffer); + if (_client_is_ready_to_login(fd)) + { + client->set_is_logged(fd); + _send_response(fd, RPL_CONNECTED(client->get_nickname())); + _reply_code = 001; + } + else + { + _reply_code = 200; + } + } } diff --git a/src/main.cpp b/src/main.cpp index 658dc6e..2f72a65 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,13 +12,14 @@ #include "Server.hpp" -int main(int argc, char **argv) +int main(int argc, char** argv) { (void)argc; (void)argv; Server server; // if (argc != 3) - // {std::cout << "Usage: " << argv[0] << " " << std::endl; return 1;} + // {std::cout << "Usage: " << argv[0] << " " << + // std::endl; return 1;} std::cout << GRE << "---- SERVER ----" << WHI << std::endl; server.init("4444", "12345"); std::cout << RED << "The Server Closed!" << WHI << std::endl; diff --git a/tests/TestInvite.cpp b/tests/TestInvite.cpp index 1932ed8..c6de6ca 100644 --- a/tests/TestInvite.cpp +++ b/tests/TestInvite.cpp @@ -12,14 +12,14 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" -Client *mockOutsideClient() +Client* mockOutsideClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(5); client->set_username("outsideUser"); client->set_nickname("outsideUser"); @@ -30,9 +30,9 @@ Client *mockOutsideClient() return client; } -Client *mockInsideClient() +Client* mockInsideClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("insideUser"); client->set_nickname("insideUser"); @@ -50,27 +50,28 @@ Test(InviteCommand, succesfully_invite_client_to_channel) Client* insideClient = mockInsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); channel->set_channel_operator(insideClient); // Add clients to the server clients list - server._clients.push_back(*outsideClient); + server._clients.push_back(*outsideClient); server._clients.push_back(*insideClient); // Add clients as channel member channel->join(insideClient); // Add channel to the server channels list - server._channels.push_back(channel); + server._channels.push_back(channel); // Invite client to channel server._handler_client_invite("outsideUser #world", 4); cr_assert(eq(int, server._reply_code, 200)); - cr_assert(eq(int, server._get_client( - outsideClient->get_fd())->is_channel_invited( - channel->get_name()), 1)); + cr_assert(eq(int, + server._get_client(outsideClient->get_fd()) + ->is_channel_invited(channel->get_name()), + 1)); } Test(InviteCommand, err_nosuchchannel) @@ -79,14 +80,14 @@ Test(InviteCommand, err_nosuchchannel) Client* insideClient = mockInsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); // Add clients to the server clients list - server._clients.push_back(*outsideClient); + server._clients.push_back(*outsideClient); server._clients.push_back(*insideClient); - + // Add channel to the server channels list - server._channels.push_back(channel); + server._channels.push_back(channel); // Invite client to channel server._handler_client_invite("outsideClient #deadworld", 4); @@ -99,16 +100,16 @@ Test(InviteCommand, err_notonchannel) Client* insideClient = mockInsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); // Add clients to the server clients list - server._clients.push_back(*outsideClient); + server._clients.push_back(*outsideClient); server._clients.push_back(*insideClient); channel->invite(outsideClient); - + // Add channel to the server channels list - server._channels.push_back(channel); + server._channels.push_back(channel); // Invite client to channel server._handler_client_invite("outsideClient #world", 4); @@ -120,7 +121,7 @@ Test(InviteCommand, err_nosuchnick) Client* insideClient = mockInsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); channel->set_channel_operator(insideClient); @@ -128,9 +129,9 @@ Test(InviteCommand, err_nosuchnick) server._clients.push_back(*insideClient); channel->invite(insideClient); - + // Add channel to the server channels list - server._channels.push_back(channel); + server._channels.push_back(channel); // Invite client to channel server._handler_client_invite("outsideClient #world", 4); @@ -142,7 +143,7 @@ Test(InviteCommand, err_noprivileges) Client* insideClient = mockInsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); // Add clients to the server clients list server._clients.push_back(*insideClient); @@ -151,19 +152,19 @@ Test(InviteCommand, err_noprivileges) channel->invite(insideClient); // Add channel to the server channels list - server._channels.push_back(channel); + server._channels.push_back(channel); // Invite client to channel server._handler_client_invite("outsideUser #world", 4); cr_assert(eq(int, server._reply_code, 481)); } - + Test(InviteCommand, err_useronchannel) { Client* insideClient = mockInsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); channel->set_channel_operator(insideClient); @@ -171,9 +172,9 @@ Test(InviteCommand, err_useronchannel) server._clients.push_back(*insideClient); channel->invite(insideClient); - + // Add channel to the server channels list - server._channels.push_back(channel); + server._channels.push_back(channel); // Invite client to channel server._handler_client_invite("insideUser #world", 4); @@ -185,7 +186,7 @@ Test(InviteCommand, err_notregistered) Client* insideClient = mockInsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); insideClient->set_is_logged(false); @@ -193,9 +194,9 @@ Test(InviteCommand, err_notregistered) server._clients.push_back(*insideClient); channel->invite(insideClient); - + // Add channel to the server channels list - server._channels.push_back(channel); + server._channels.push_back(channel); // Invite client to channel server._handler_client_invite("insideUser #world", 4); diff --git a/tests/TestJoin.cpp b/tests/TestJoin.cpp index f6b7597..e37f9ef 100644 --- a/tests/TestJoin.cpp +++ b/tests/TestJoin.cpp @@ -12,15 +12,14 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" - -Client *mockOutsideClient() +Client* mockOutsideClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(6); client->set_username("outsideUser"); client->set_nickname("outsideUser"); @@ -31,9 +30,9 @@ Client *mockOutsideClient() return client; } -Client *mockCommonClient() +Client* mockCommonClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(5); client->set_username("trollUser"); client->set_nickname("trollUser"); @@ -44,9 +43,9 @@ Client *mockCommonClient() return client; } -Client *mockOperatorClient() +Client* mockOperatorClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("channelOperator"); client->set_nickname("channelOperator"); @@ -58,7 +57,4 @@ Client *mockOperatorClient() return client; } - -Test(JoinCommand, join_successfully) -{ -} \ No newline at end of file +Test(JoinCommand, join_successfully) {} \ No newline at end of file diff --git a/tests/TestKick.cpp b/tests/TestKick.cpp index 8ec3bd8..ac37e53 100644 --- a/tests/TestKick.cpp +++ b/tests/TestKick.cpp @@ -12,14 +12,14 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" -Client *mockOutsideClient() +Client* mockOutsideClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(6); client->set_username("outsideUser"); client->set_nickname("outsideUser"); @@ -30,9 +30,9 @@ Client *mockOutsideClient() return client; } -Client *mockCommonClient() +Client* mockCommonClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(5); client->set_username("trollUser"); client->set_nickname("trollUser"); @@ -43,9 +43,9 @@ Client *mockCommonClient() return client; } -Client *mockOperatorClient() +Client* mockOperatorClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("channelOperator"); client->set_nickname("channelOperator"); @@ -63,7 +63,7 @@ Test(KickCommand, kick_successfully_no_comments) Client* channelOperator = mockOperatorClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); // Add clients to the server clients list server._clients.push_back(*troll); @@ -78,14 +78,15 @@ Test(KickCommand, kick_successfully_no_comments) // to the server channels list AFTER setting the operator channelOperator->set_is_operator(true); channel->set_channel_operator(channelOperator); - + // Add channel to the server channels list server._channels.push_back(channel); // Kick troll from the channel server._handler_client_kick("#world trollUser", 4); cr_assert(eq(int, server._reply_code, 200)); - cr_assert(eq(int, server._get_channel(channel->get_name())->get_clients_size(), 1)); + cr_assert(eq( + int, server._get_channel(channel->get_name())->get_clients_size(), 1)); } Test(KickCommand, kick_successfully_with_comments) @@ -94,7 +95,7 @@ Test(KickCommand, kick_successfully_with_comments) Client* channelOperator = mockOperatorClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); // Add clients to the server clients list server._clients.push_back(*troll); @@ -109,14 +110,15 @@ Test(KickCommand, kick_successfully_with_comments) // to the server channels list AFTER setting the operator channelOperator->set_is_operator(true); channel->set_channel_operator(channelOperator); - + // Add channel to the server channels list server._channels.push_back(channel); // Print get_operator_clients /*std::vector operator_clients = channel->get_operator_clients(); - for (std::vector::const_iterator it = operator_clients.begin(); it != operator_clients.end(); ++it) + for (std::vector::const_iterator it = operator_clients.begin(); it + != operator_clients.end(); ++it) { std::cout << (*it)->get_nickname() << std::endl; std::cout << (*it)->get_fd() << std::endl; @@ -126,7 +128,8 @@ Test(KickCommand, kick_successfully_with_comments) // Kick troll from the channel server._handler_client_kick("#world trollUser trolou", 4); cr_assert(eq(int, server._reply_code, 200)); - cr_assert(eq(int, server._get_channel(channel->get_name())->get_clients_size(), 1)); + cr_assert(eq( + int, server._get_channel(channel->get_name())->get_clients_size(), 1)); } /* Test(KickCommand, err_needmoreparams) @@ -145,9 +148,9 @@ Test(KickCommand, kick_successfully_with_comments) channel->invite(troll); channel->invite(channelOperator); - // Set client channelOperator as channel operator + // Set client channelOperator as channel operator channel->set_channel_operator(channelOperator); - + // Add channel to the server channels list server._channels.push_back(channel); @@ -162,7 +165,7 @@ Test(KickCommand, err_nosuchchannel) Client* channelOperator = mockOperatorClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); // Add clients to the server clients list server._clients.push_back(*troll); @@ -172,9 +175,9 @@ Test(KickCommand, err_nosuchchannel) channel->invite(troll); channel->invite(channelOperator); - // Set client channelOperator as channel operator + // Set client channelOperator as channel operator channel->set_channel_operator(channelOperator); - + // Add channel to the server channels list server._channels.push_back(channel); @@ -190,7 +193,7 @@ Test(KickCommand, err_notonchannel) Client* outsideUser = mockOutsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); // Add clients to the server clients list server._clients.push_back(*troll); @@ -201,9 +204,9 @@ Test(KickCommand, err_notonchannel) channel->invite(troll); channel->invite(channelOperator); - // Set client channelOperator as channel operator + // Set client channelOperator as channel operator channel->set_channel_operator(channelOperator); - + // Add channel to the server channels list server._channels.push_back(channel); @@ -218,7 +221,7 @@ Test(KickCommand, err_chanoprivsneeded) Client* channelOperator = mockOperatorClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); channelOperator->set_is_operator(false); @@ -229,7 +232,7 @@ Test(KickCommand, err_chanoprivsneeded) // Add clients as channel member channel->invite(troll); channel->invite(channelOperator); - + // Add channel to the server channels list server._channels.push_back(channel); @@ -244,7 +247,7 @@ Test(KickCommand, err_nosuchnick) Client* channelOperator = mockOperatorClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); channelOperator->set_is_operator(false); @@ -261,7 +264,7 @@ Test(KickCommand, err_nosuchnick) // to the server channels list AFTER setting the operator channelOperator->set_is_operator(true); channel->set_channel_operator(channelOperator); - + // Add channel to the server channels list server._channels.push_back(channel); @@ -277,7 +280,7 @@ Test(KickCommand, err_usernotinchannel) Client* outsideUser = mockOutsideClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); channelOperator->set_is_operator(false); @@ -295,7 +298,7 @@ Test(KickCommand, err_usernotinchannel) // to the server channels list AFTER setting the operator channelOperator->set_is_operator(true); channel->set_channel_operator(channelOperator); - + // Add channel to the server channels list server._channels.push_back(channel); diff --git a/tests/TestMarvinBot.cpp b/tests/TestMarvinBot.cpp index 3310438..f67d519 100644 --- a/tests/TestMarvinBot.cpp +++ b/tests/TestMarvinBot.cpp @@ -15,9 +15,9 @@ #define private public #include "MarvinBot.hpp" -Client *mockClient() +Client* mockClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(5); client->set_username("trollUser"); client->set_nickname("trollUser"); @@ -30,7 +30,7 @@ Client *mockClient() Test(MarvinBotCommand, user_is_not_in_any_channel) { - Client *client = mockClient(); + Client* client = mockClient(); Server server; @@ -43,10 +43,10 @@ Test(MarvinBotCommand, user_is_not_in_any_channel) Test(MarvinBotCommand, user_is_in_any_channel) { - Client *client = mockClient(); + Client* client = mockClient(); Server server; - Channel *channel = new Channel("#world"); + Channel* channel = new Channel("#world"); server._clients.push_back(*client); diff --git a/tests/TestMode.cpp b/tests/TestMode.cpp index 6423546..211d2a9 100644 --- a/tests/TestMode.cpp +++ b/tests/TestMode.cpp @@ -9,4 +9,3 @@ /* Updated: 2024/05/30 16:59:55 by gilmar ### ########.fr */ /* */ /* ************************************************************************** */ - diff --git a/tests/TestNick.cpp b/tests/TestNick.cpp index c332250..e306b72 100644 --- a/tests/TestNick.cpp +++ b/tests/TestNick.cpp @@ -12,8 +12,8 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" @@ -26,11 +26,11 @@ * 5. O comando NICK é recebido e o nickname do cliente está em uso. * 6. O comando NICK é recebido e o nickname do cliente é alterado. * 7. O comando NICK é recebido e o cliente está pronto para logar. -*/ + */ -Client *mockClient() +Client* mockClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("Username"); client->set_nickname("Nickname"); @@ -43,7 +43,7 @@ Client *mockClient() /* * 1. O comando NICK é recebido sem parâmetros suficientes. -*/ + */ Test(NickCommand, err_needmoreparams) { Client* client = mockClient(); @@ -51,13 +51,13 @@ Test(NickCommand, err_needmoreparams) Server server; server._clients.push_back(*client); server._handler_client_nickname("", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 461)); } /* * 2. O comando NICK é recebido e o cliente não está registrado. -*/ + */ Test(NickCommand, err_notregistered) { Client* client = mockClient(); @@ -66,13 +66,13 @@ Test(NickCommand, err_notregistered) Server server; server._clients.push_back(*client); server._handler_client_nickname(client->get_nickname(), client->get_fd()); - + cr_assert(eq(int, server._reply_code, 451)); } /* * 3. O comando NICK é recebido e o nickname do cliente é inválido. -*/ + */ Test(NickCommand, err_erroneusnick_1) { Client* client = mockClient(); @@ -81,7 +81,7 @@ Test(NickCommand, err_erroneusnick_1) Server server; server._clients.push_back(*client); server._handler_client_nickname("new_nickname", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 432)); } @@ -93,7 +93,7 @@ Test(NickCommand, err_erroneusnick_2) Server server; server._clients.push_back(*client); server._handler_client_nickname("$Gilmar", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 432)); } @@ -105,7 +105,7 @@ Test(NickCommand, err_erroneusnick_3) Server server; server._clients.push_back(*client); server._handler_client_nickname("Ygor%", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 432)); } @@ -117,13 +117,13 @@ Test(NickCommand, err_erroneusnick_4) Server server; server._clients.push_back(*client); server._handler_client_nickname("Car#los", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 432)); } /* * 4. O comando NICK é recebido e o cliente está registrado. -*/ + */ Test(NickCommand, success_setnickname) { Client* client = mockClient(); @@ -132,18 +132,18 @@ Test(NickCommand, success_setnickname) Server server; server._clients.push_back(*client); server._handler_client_nickname("newNickname", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 200)); } /* * 5. O comando NICK é recebido e o nickname do cliente está em uso. -*/ + */ Test(NickCommand, err_nickinuse) { Client* client = mockClient(); client->set_is_authenticated(true); - + Client* client1 = mockClient(); client1->set_fd(5); client1->set_is_authenticated(true); @@ -152,13 +152,13 @@ Test(NickCommand, err_nickinuse) server._clients.push_back(*client); server._clients.push_back(*client1); server._handler_client_nickname(client1->get_nickname(), client1->get_fd()); - + cr_assert(eq(int, server._reply_code, 433)); } /* * 6. O comando NICK é recebido e o nickname do cliente é alterado. -*/ + */ Test(NickCommand, success_changenickname) { Client* client = mockClient(); @@ -167,13 +167,13 @@ Test(NickCommand, success_changenickname) Server server; server._clients.push_back(*client); server._handler_client_nickname(client->get_nickname(), client->get_fd()); - + cr_assert(eq(int, server._reply_code, 200)); } /* * 7. O comando NICK é recebido e o cliente está pronto para logar. -*/ + */ Test(NickCommand, success_readytologin) { Client* client = mockClient(); @@ -183,6 +183,6 @@ Test(NickCommand, success_readytologin) Server server; server._clients.push_back(*client); server._handler_client_nickname(client->get_nickname(), client->get_fd()); - + cr_assert(eq(int, server._reply_code, 001)); } diff --git a/tests/TestPart.cpp b/tests/TestPart.cpp index 162f6b0..3c89d34 100644 --- a/tests/TestPart.cpp +++ b/tests/TestPart.cpp @@ -12,14 +12,14 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" -Client *genericClient() +Client* genericClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(6); client->set_username("soAndSoUser"); client->set_nickname("soAndSoUser"); @@ -30,9 +30,9 @@ Client *genericClient() return client; } -Client *toPartClient() +Client* toPartClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("toPartUser"); client->set_nickname("toPartUser"); @@ -46,12 +46,12 @@ Client *toPartClient() Test(PartCommand, part_successfully) { - Client *toPart = toPartClient(); - Client *channelMember = genericClient(); + Client* toPart = toPartClient(); + Client* channelMember = genericClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*toPart); server._clients.push_back(*channelMember); @@ -66,18 +66,18 @@ Test(PartCommand, part_successfully) server._handler_client_part("#channel", toPart->get_fd()); cr_assert(eq(int, server._reply_code, 200)); - cr_assert(eq(int, server._get_channel(channel->get_name())->get_clients_size(), 1)); + cr_assert(eq( + int, server._get_channel(channel->get_name())->get_clients_size(), 1)); } - Test(PartCommand, err_nosuchchannel) { - Client *toPart = toPartClient(); - Client *channelMember = genericClient(); + Client* toPart = toPartClient(); + Client* channelMember = genericClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*toPart); server._clients.push_back(*channelMember); @@ -96,12 +96,12 @@ Test(PartCommand, err_nosuchchannel) Test(PartCommand, err_notonchannel) { - Client *toPart = toPartClient(); - Client *channelMember = genericClient(); + Client* toPart = toPartClient(); + Client* channelMember = genericClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*toPart); server._clients.push_back(*channelMember); @@ -119,12 +119,12 @@ Test(PartCommand, err_notonchannel) Test(PartCommand, err_notregistered) { - Client *toPart = toPartClient(); - Client *channelMember = genericClient(); + Client* toPart = toPartClient(); + Client* channelMember = genericClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); toPart->set_is_logged(false); diff --git a/tests/TestPass.cpp b/tests/TestPass.cpp index 75fe437..587df8c 100644 --- a/tests/TestPass.cpp +++ b/tests/TestPass.cpp @@ -12,8 +12,8 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" @@ -27,81 +27,81 @@ * 6. O comando PASS é recebido e o cliente está logado. * 7. O comando PASS é recebido e o cliente não está autenticado. * 8. O comando PASS é recebido e o cliente está autenticado. - * -*/ + * + */ -Client *mockClient() +Client* mockClient() { - Client *client = new Client(); - client->set_fd(4); - client->set_username("Username"); - client->set_nickname("Nickname"); - client->set_password("Password"); - client->set_buffer("Pass password"); - client->set_is_logged(true); - client->set_is_authenticated(true); - client->set_is_operator(false); - return client; + Client* client = new Client(); + client->set_fd(4); + client->set_username("Username"); + client->set_nickname("Nickname"); + client->set_password("Password"); + client->set_buffer("Pass password"); + client->set_is_logged(true); + client->set_is_authenticated(true); + client->set_is_operator(false); + return client; } /* * 1. O comando PASS é recebido sem parâmetros suficientes. -*/ + */ Test(ServerHandlerClientPassword, TestPassWithoutEnoughParameters) { - Client *client = mockClient(); - - Server server; - server._clients.push_back(*client); - server._handler_client_password("", client->get_fd()); - - cr_assert_eq(server._reply_code, 461); + Client* client = mockClient(); + + Server server; + server._clients.push_back(*client); + server._handler_client_password("", client->get_fd()); + + cr_assert_eq(server._reply_code, 461); } /* * 2. O comando PASS é recebido e o cliente já está autenticado. -*/ + */ Test(ServerHandlerClientPassword, TestPassClientIsAuthenticated) { - Client *client = mockClient(); - client->set_is_authenticated(true); + Client* client = mockClient(); + client->set_is_authenticated(true); + + Server server; + server._password = "Password"; + server._clients.push_back(*client); + server._handler_client_password("Password", client->get_fd()); - Server server; - server._password = "Password"; - server._clients.push_back(*client); - server._handler_client_password("Password", client->get_fd()); - - cr_assert_eq(server._reply_code, 462); + cr_assert_eq(server._reply_code, 462); } /* * 3. O comando PASS é recebido e a senha do cliente está incorreta. -*/ + */ Test(ServerHandlerClientPassword, TestPassIncorrectPassword) { - Client *client = mockClient(); - client->set_is_authenticated(false); - - Server server; - server._password = "Password"; - server._clients.push_back(*client); - server._handler_client_password("IncorrectPassword", client->get_fd()); - - cr_assert_eq(server._reply_code, 464); + Client* client = mockClient(); + client->set_is_authenticated(false); + + Server server; + server._password = "Password"; + server._clients.push_back(*client); + server._handler_client_password("IncorrectPassword", client->get_fd()); + + cr_assert_eq(server._reply_code, 464); } /* * 4. O comando PASS é recebido e a senha do cliente está correta. -*/ + */ Test(ServerHandlerClientPassword, TestPassCorrectPassword) { - Client *client = mockClient(); - client->set_is_authenticated(false); - - Server server; - server._password = "Password"; - server._clients.push_back(*client); - server._handler_client_password("Password", client->get_fd()); - - cr_assert_eq(server._reply_code, 200); + Client* client = mockClient(); + client->set_is_authenticated(false); + + Server server; + server._password = "Password"; + server._clients.push_back(*client); + server._handler_client_password("Password", client->get_fd()); + + cr_assert_eq(server._reply_code, 200); } \ No newline at end of file diff --git a/tests/TestPrivmsg.cpp b/tests/TestPrivmsg.cpp index a0f6144..b1d7136 100644 --- a/tests/TestPrivmsg.cpp +++ b/tests/TestPrivmsg.cpp @@ -12,14 +12,14 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" -Client *secondReceiver() +Client* secondReceiver() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(6); client->set_username("secondUser"); client->set_nickname("secondUser"); @@ -30,9 +30,9 @@ Client *secondReceiver() return client; } -Client *firstReceiver() +Client* firstReceiver() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(5); client->set_username("firstUser"); client->set_nickname("firstUser"); @@ -43,9 +43,9 @@ Client *firstReceiver() return client; } -Client *senderClient() +Client* senderClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("senderUser"); client->set_nickname("senderUser"); @@ -59,9 +59,9 @@ Client *senderClient() Test(PrivmsgCommand, privmsg_successfully_single_client) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -75,9 +75,9 @@ Test(PrivmsgCommand, privmsg_successfully_single_client) Test(PrivmsgCommand, privmsg_successfully_two_clients) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -91,9 +91,9 @@ Test(PrivmsgCommand, privmsg_successfully_two_clients) Test(PrivmsgCommand, privmsg_successfully_single_channel) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -101,8 +101,8 @@ Test(PrivmsgCommand, privmsg_successfully_single_channel) server._clients.push_back(*first); server._clients.push_back(*second); - Channel *channel = new Channel("#brazil"); - + Channel* channel = new Channel("#brazil"); + channel->invite(sender); server._channels.push_back(channel); @@ -112,9 +112,9 @@ Test(PrivmsgCommand, privmsg_successfully_single_channel) Test(PrivmsgCommand, privmsg_successfully_three_channels) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -122,10 +122,10 @@ Test(PrivmsgCommand, privmsg_successfully_three_channels) server._clients.push_back(*first); server._clients.push_back(*second); - Channel *ch_brazil = new Channel("#brazil"); - Channel *ch_france = new Channel("#france"); - Channel *ch_spain = new Channel("#spain"); - + Channel* ch_brazil = new Channel("#brazil"); + Channel* ch_france = new Channel("#france"); + Channel* ch_spain = new Channel("#spain"); + ch_brazil->invite(sender); ch_france->invite(sender); ch_france->invite(first); @@ -142,9 +142,9 @@ Test(PrivmsgCommand, privmsg_successfully_three_channels) Test(PrivmsgCommand, privmsg_successfully_mixed_channel_user) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -152,10 +152,10 @@ Test(PrivmsgCommand, privmsg_successfully_mixed_channel_user) server._clients.push_back(*first); server._clients.push_back(*second); - Channel *ch_brazil = new Channel("#brazil"); - Channel *ch_france = new Channel("#france"); - Channel *ch_spain = new Channel("#spain"); - + Channel* ch_brazil = new Channel("#brazil"); + Channel* ch_france = new Channel("#france"); + Channel* ch_spain = new Channel("#spain"); + ch_brazil->invite(sender); ch_france->invite(sender); ch_spain->invite(sender); @@ -163,15 +163,16 @@ Test(PrivmsgCommand, privmsg_successfully_mixed_channel_user) server._channels.push_back(ch_france); server._channels.push_back(ch_spain); - server._handler_client_privmsg("#brazil,firstUser,#france,secondUser,#spain :Hello, WORLD!", 4); + server._handler_client_privmsg( + "#brazil,firstUser,#france,secondUser,#spain :Hello, WORLD!", 4); cr_assert(eq(int, server._reply_code, 0)); } Test(PrivmsgCommand, err_notregistered) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -187,9 +188,9 @@ Test(PrivmsgCommand, err_notregistered) Test(PrivmsgCommand, err_nosuchchannel) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -197,10 +198,10 @@ Test(PrivmsgCommand, err_nosuchchannel) server._clients.push_back(*first); server._clients.push_back(*second); - Channel *ch_brazil = new Channel("#brazil"); - Channel *ch_france = new Channel("#france"); - Channel *ch_spain = new Channel("#spain"); - + Channel* ch_brazil = new Channel("#brazil"); + Channel* ch_france = new Channel("#france"); + Channel* ch_spain = new Channel("#spain"); + ch_brazil->invite(sender); ch_france->invite(sender); ch_spain->invite(sender); @@ -208,15 +209,16 @@ Test(PrivmsgCommand, err_nosuchchannel) server._channels.push_back(ch_france); server._channels.push_back(ch_spain); - server._handler_client_privmsg("#brazil,firstUser,#neptune,secondUser,#spain :Hello, WORLD!", 4); + server._handler_client_privmsg( + "#brazil,firstUser,#neptune,secondUser,#spain :Hello, WORLD!", 4); cr_assert(eq(int, server._reply_code, 403)); } Test(PrivmsgCommand, err_notonchannel) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -224,25 +226,26 @@ Test(PrivmsgCommand, err_notonchannel) server._clients.push_back(*first); server._clients.push_back(*second); - Channel *ch_brazil = new Channel("#brazil"); - Channel *ch_france = new Channel("#france"); - Channel *ch_spain = new Channel("#spain"); - + Channel* ch_brazil = new Channel("#brazil"); + Channel* ch_france = new Channel("#france"); + Channel* ch_spain = new Channel("#spain"); + ch_brazil->invite(sender); ch_spain->invite(sender); server._channels.push_back(ch_brazil); server._channels.push_back(ch_france); server._channels.push_back(ch_spain); - server._handler_client_privmsg("#brazil,firstUser,#france,secondUser,#spain :Hello, WORLD!", 4); + server._handler_client_privmsg( + "#brazil,firstUser,#france,secondUser,#spain :Hello, WORLD!", 4); cr_assert(eq(int, server._reply_code, 442)); } Test(PrivmsgCommand, err_nosuchnick) { - Client *sender = senderClient(); - Client *first = firstReceiver(); - Client *second = secondReceiver(); + Client* sender = senderClient(); + Client* first = firstReceiver(); + Client* second = secondReceiver(); Server server; @@ -250,10 +253,10 @@ Test(PrivmsgCommand, err_nosuchnick) server._clients.push_back(*first); server._clients.push_back(*second); - Channel *ch_brazil = new Channel("#brazil"); - Channel *ch_france = new Channel("#france"); - Channel *ch_spain = new Channel("#spain"); - + Channel* ch_brazil = new Channel("#brazil"); + Channel* ch_france = new Channel("#france"); + Channel* ch_spain = new Channel("#spain"); + ch_brazil->invite(sender); ch_france->invite(sender); ch_spain->invite(sender); @@ -261,6 +264,7 @@ Test(PrivmsgCommand, err_nosuchnick) server._channels.push_back(ch_france); server._channels.push_back(ch_spain); - server._handler_client_privmsg("#brazil,thirdUser,#france,secondUser,#spain :Hello, WORLD!", 4); + server._handler_client_privmsg( + "#brazil,thirdUser,#france,secondUser,#spain :Hello, WORLD!", 4); cr_assert(eq(int, server._reply_code, 401)); } diff --git a/tests/TestQuit.cpp b/tests/TestQuit.cpp index 2dc819d..562cd03 100644 --- a/tests/TestQuit.cpp +++ b/tests/TestQuit.cpp @@ -12,14 +12,14 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" -Client *genericClient() +Client* genericClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(6); client->set_username("soAndSoUser"); client->set_nickname("soAndSoUser"); @@ -30,9 +30,9 @@ Client *genericClient() return client; } -Client *toPartClient() +Client* toPartClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("toPartUser"); client->set_nickname("toPartUser"); @@ -45,21 +45,23 @@ Client *toPartClient() Test(QuitCommand, non_client_operator_quits_successfully) { - Client *toPart = toPartClient(); - Client *channelMember = genericClient(); + Client* toPart = toPartClient(); + Client* channelMember = genericClient(); Server server; std::vector channels = { - new Channel("#one"), new Channel("#two"), new Channel("#three") - }; + new Channel("#one"), new Channel("#two"), new Channel("#three")}; toPart->set_is_operator(false); server._clients.push_back(*toPart); server._clients.push_back(*channelMember); - for (std::vector::iterator it = channels.begin(); it != channels.end(); ++it) { + for (std::vector::iterator it = channels.begin(); + it != channels.end(); + ++it) + { (*it)->join(toPart); (*it)->join(channelMember); server._channels.push_back(*it); @@ -68,28 +70,33 @@ Test(QuitCommand, non_client_operator_quits_successfully) server._handler_client_quit("It's time to go", toPart->get_fd()); cr_assert(eq(int, server._reply_code, 301)); - for (std::vector::iterator it = server._channels.begin(); it != server._channels.end(); ++it) { + for (std::vector::iterator it = server._channels.begin(); + it != server._channels.end(); + ++it) + { cr_assert(eq(int, (*it)->get_clients_size(), 1)); } } Test(QuitCommand, client_operator_quits_successfully) { - Client *toPart = toPartClient(); - Client *channelMember = genericClient(); + Client* toPart = toPartClient(); + Client* channelMember = genericClient(); Server server; std::vector channels = { - new Channel("#one"), new Channel("#two"), new Channel("#three") - }; + new Channel("#one"), new Channel("#two"), new Channel("#three")}; - //toPart->set_is_operator(true); + // toPart->set_is_operator(true); server._clients.push_back(*toPart); server._clients.push_back(*channelMember); - for (std::vector::iterator it = channels.begin(); it != channels.end(); ++it) { + for (std::vector::iterator it = channels.begin(); + it != channels.end(); + ++it) + { (*it)->join(toPart); (*it)->join(channelMember); (*it)->set_channel_operator(toPart); @@ -98,13 +105,20 @@ Test(QuitCommand, client_operator_quits_successfully) server._handler_client_quit("It's time to go", toPart->get_fd()); - std::cout << "clients after quit: " << server._get_channel("#one")->get_client_names() << std::endl; + std::cout << "clients after quit: " + << server._get_channel("#one")->get_client_names() << std::endl; cr_assert(eq(int, server._reply_code, 301)); - for (std::vector::iterator it = server._channels.begin(); it != server._channels.end(); ++it) { + for (std::vector::iterator it = server._channels.begin(); + it != server._channels.end(); + ++it) + { cr_assert(eq(int, (*it)->get_clients_size(), 1)); } - for (std::vector::iterator it = server._channels.begin(); it != server._channels.end(); ++it) { + for (std::vector::iterator it = server._channels.begin(); + it != server._channels.end(); + ++it) + { cr_assert(eq(int, (*it)->get_operator_clients().size(), 0)); } } diff --git a/tests/TestSplitMessage.cpp b/tests/TestSplitMessage.cpp index 842de51..bfd7ee0 100644 --- a/tests/TestSplitMessage.cpp +++ b/tests/TestSplitMessage.cpp @@ -11,56 +11,86 @@ /* ************************************************************************** */ #include -#include "Utils.hpp" -#include #include #include +#include +#include "Utils.hpp" -Test(split_message, should_split_message_into_receivers_and_text_1) { - std::string message = "receiver1,receiver2,receiver3 This is a test message"; +Test(split_message, should_split_message_into_receivers_and_text_1) +{ + std::string message = + "receiver1,receiver2,receiver3 This is a test message"; - std::pair, std::string> result = split_message(message); + std::pair, std::string> result = + split_message(message); - std::vector expectedReceivers = {"receiver1", "receiver2", "receiver3"}; + std::vector expectedReceivers = { + "receiver1", "receiver2", "receiver3"}; std::string expectedText = "This is a test message"; - cr_assert_eq(result.first.size(), expectedReceivers.size(), "Number of receivers does not match"); - for (size_t i = 0; i < expectedReceivers.size(); i++) { - cr_assert_str_eq(result.first[i].c_str(), expectedReceivers[i].c_str(), "Receiver %zu does not match", i); + cr_assert_eq(result.first.size(), + expectedReceivers.size(), + "Number of receivers does not match"); + for (size_t i = 0; i < expectedReceivers.size(); i++) + { + cr_assert_str_eq(result.first[i].c_str(), + expectedReceivers[i].c_str(), + "Receiver %zu does not match", + i); } - cr_assert_str_eq(result.second.c_str(), expectedText.c_str(), "Text does not match"); + cr_assert_str_eq( + result.second.c_str(), expectedText.c_str(), "Text does not match"); } -Test(split_message, should_split_message_into_receivers_and_text_2) { - std::string message = "receiver1,receiver2,receiver3, This is a test message"; +Test(split_message, should_split_message_into_receivers_and_text_2) +{ + std::string message = + "receiver1,receiver2,receiver3, This is a test message"; - std::pair, std::string> result = split_message(message); + std::pair, std::string> result = + split_message(message); - std::vector expectedReceivers = {"receiver1", "receiver2", "receiver3"}; + std::vector expectedReceivers = { + "receiver1", "receiver2", "receiver3"}; std::string expectedText = "This is a test message"; - cr_assert_eq(result.first.size(), expectedReceivers.size(), "Number of receivers does not match"); - for (size_t i = 0; i < expectedReceivers.size(); i++) { - cr_assert_str_eq(result.first[i].c_str(), expectedReceivers[i].c_str(), "Receiver %zu does not match", i); + cr_assert_eq(result.first.size(), + expectedReceivers.size(), + "Number of receivers does not match"); + for (size_t i = 0; i < expectedReceivers.size(); i++) + { + cr_assert_str_eq(result.first[i].c_str(), + expectedReceivers[i].c_str(), + "Receiver %zu does not match", + i); } - cr_assert_str_eq(result.second.c_str(), expectedText.c_str(), "Text does not match"); + cr_assert_str_eq( + result.second.c_str(), expectedText.c_str(), "Text does not match"); } - -Test(split_message, should_split_message_into_receivers_and_text_3) { +Test(split_message, should_split_message_into_receivers_and_text_3) +{ std::string message = "channel This is a test message"; - std::pair, std::string> result = split_message(message); + std::pair, std::string> result = + split_message(message); std::vector expectedReceivers = {"channel"}; std::string expectedText = "This is a test message"; - cr_assert_eq(result.first.size(), expectedReceivers.size(), "Number of receivers does not match"); - for (size_t i = 0; i < expectedReceivers.size(); i++) { - cr_assert_str_eq(result.first[i].c_str(), expectedReceivers[i].c_str(), "Receiver %zu does not match", i); + cr_assert_eq(result.first.size(), + expectedReceivers.size(), + "Number of receivers does not match"); + for (size_t i = 0; i < expectedReceivers.size(); i++) + { + cr_assert_str_eq(result.first[i].c_str(), + expectedReceivers[i].c_str(), + "Receiver %zu does not match", + i); } - cr_assert_str_eq(result.second.c_str(), expectedText.c_str(), "Text does not match"); + cr_assert_str_eq( + result.second.c_str(), expectedText.c_str(), "Text does not match"); } diff --git a/tests/TestTopic.cpp b/tests/TestTopic.cpp index 2ed68f0..4652ee6 100644 --- a/tests/TestTopic.cpp +++ b/tests/TestTopic.cpp @@ -12,23 +12,24 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" /* ** TOPIC #channel -** - mostrar o tópico do canal se houver (332), caso contrário, o canal não tem tópico (331) +** - mostrar o tópico do canal se houver (332), caso contrário, o canal não tem +*tópico (331) ** ** TOPIC #channel newtopic ** - para alterar o tópico, o cliente deve ser operador do canal (482) ** - mode -t permite ou não alterar o tópico do canal */ -Client *mockChannelMemberClient() +Client* mockChannelMemberClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("channelOperator"); client->set_nickname("channelOperator"); @@ -42,7 +43,7 @@ Client *mockChannelMemberClient() Test(TopicCommand, err_needmoreparams) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; server._clients.push_back(*client); @@ -52,7 +53,7 @@ Test(TopicCommand, err_needmoreparams) Test(TopicCommand, err_notregistered) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; client->set_is_logged(false); @@ -64,7 +65,7 @@ Test(TopicCommand, err_notregistered) Test(TopicCommand, err_nosuchchannel) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; server._clients.push_back(*client); @@ -74,10 +75,10 @@ Test(TopicCommand, err_nosuchchannel) Test(TopicCommand, rpl_notopic) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*client); @@ -96,10 +97,10 @@ Test(TopicCommand, rpl_notopic) Test(TopicCommand, err_notoperator) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*client); @@ -116,10 +117,10 @@ Test(TopicCommand, err_notoperator) Test(TopicCommand, rpl_topic_set_first_topic) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*client); @@ -136,10 +137,10 @@ Test(TopicCommand, rpl_topic_set_first_topic) Test(TopicCommand, rpl_topic_set_second_topic) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*client); @@ -158,10 +159,10 @@ Test(TopicCommand, rpl_topic_set_second_topic) Test(TopicCommand, cannot_set_topic_with_topic_restriction) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*client); @@ -179,10 +180,10 @@ Test(TopicCommand, cannot_set_topic_with_topic_restriction) Test(TopicCommand, err_notonchannel) { - Client *client = mockChannelMemberClient(); + Client* client = mockChannelMemberClient(); Server server; - Channel *channel = new Channel("#channel"); + Channel* channel = new Channel("#channel"); server._clients.push_back(*client); diff --git a/tests/TestUser.cpp b/tests/TestUser.cpp index a824715..bac33bc 100644 --- a/tests/TestUser.cpp +++ b/tests/TestUser.cpp @@ -12,8 +12,8 @@ #include #include -#include "Client.hpp" #include "Channel.hpp" +#include "Client.hpp" #define private public #include "Server.hpp" @@ -24,12 +24,12 @@ * 3. O comando USER é recebido e o cliente já está registrado. * 4. O comando USER é recebido e o cliente está pronto para fazer login. * 5. O comando USER é recebido e o cliente não está pronto para fazer login. - * -*/ + * + */ -Client *mockClient() +Client* mockClient() { - Client *client = new Client(); + Client* client = new Client(); client->set_fd(4); client->set_username("Username"); client->set_nickname("Nickname"); @@ -42,7 +42,7 @@ Client *mockClient() /* * 1. O comando USER é recebido sem parâmetros suficientes. -*/ + */ Test(UserCommand, err_needmoreparams) { Client* client = mockClient(); @@ -50,13 +50,13 @@ Test(UserCommand, err_needmoreparams) Server server; server._clients.push_back(*client); server._handler_client_username("", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 461)); } /* * 2. O comando USER é recebido e o cliente não está registrado. -*/ + */ Test(UserCommand, err_notregistered) { Client* client = mockClient(); @@ -66,13 +66,13 @@ Test(UserCommand, err_notregistered) Server server; server._clients.push_back(*client); server._handler_client_username(client->get_username(), client->get_fd()); - + cr_assert(eq(int, server._reply_code, 451)); } /* * 3. O comando USER é recebido e o cliente já está registrado. -*/ + */ Test(UserCommand, err_alreadyregistered) { Client* client = mockClient(); @@ -80,13 +80,13 @@ Test(UserCommand, err_alreadyregistered) Server server; server._clients.push_back(*client); server._handler_client_username(client->get_username(), client->get_fd()); - + cr_assert(eq(int, server._reply_code, 462)); } /* * 4. O comando USER é recebido e o cliente está pronto para fazer login. -*/ + */ Test(UserCommand, success_readytologin) { Client* client = mockClient(); @@ -97,13 +97,13 @@ Test(UserCommand, success_readytologin) Server server; server._clients.push_back(*client); server._handler_client_username("Username", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 001)); } /* * 5. O comando USER é recebido e o cliente não está pronto para fazer login. -*/ + */ Test(UserCommand, success_notreadytologin) { Client* client = mockClient(); @@ -115,6 +115,6 @@ Test(UserCommand, success_notreadytologin) Server server; server._clients.push_back(*client); server._handler_client_username("Username", client->get_fd()); - + cr_assert(eq(int, server._reply_code, 200)); } diff --git a/tests/Utils.cpp b/tests/Utils.cpp index 5c221de..64ed793 100644 --- a/tests/Utils.cpp +++ b/tests/Utils.cpp @@ -12,12 +12,14 @@ #include "Utils.hpp" -#include -#include #include +#include #include +#include -std::pair, std::string> split_message(const std::string& message) { +std::pair, std::string> split_message( + const std::string& message) +{ std::istringstream iss(message); std::string receiversStr, text; @@ -29,7 +31,8 @@ std::pair, std::string> split_message(const std::string std::vector receivers; std::istringstream receiversStream(receiversStr); std::string receiver; - while (std::getline(receiversStream, receiver, ',')) { + while (std::getline(receiversStream, receiver, ',')) + { receivers.push_back(receiver); } diff --git a/tests/Utils.hpp b/tests/Utils.hpp index 40ab5cb..f156eab 100644 --- a/tests/Utils.hpp +++ b/tests/Utils.hpp @@ -11,15 +11,15 @@ /* ************************************************************************** */ #ifndef UTILS_HPP -# define UTILS_HPP +#define UTILS_HPP -# define EPSILON 0.0001 +#define EPSILON 0.0001 -#include -#include #include +#include +#include std::pair, std::string> split_message( const std::string& message); -# endif // UTILS_HPP \ No newline at end of file +#endif // UTILS_HPP \ No newline at end of file