diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index a769c0e..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "files.associations": { - "iostream": "cpp", - "vector": "cpp", - "ostream": "cpp", - "__bit_reference": "cpp", - "__config": "cpp", - "__debug": "cpp", - "__errc": "cpp", - "__functional_base": "cpp", - "__hash_table": "cpp", - "__locale": "cpp", - "__mutex_base": "cpp", - "__node_handle": "cpp", - "__nullptr": "cpp", - "__split_buffer": "cpp", - "__string": "cpp", - "__threading_support": "cpp", - "__tuple": "cpp", - "algorithm": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "bitset": "cpp", - "cctype": "cpp", - "chrono": "cpp", - "cmath": "cpp", - "complex": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "exception": "cpp", - "functional": "cpp", - "initializer_list": "cpp", - "ios": "cpp", - "iosfwd": "cpp", - "istream": "cpp", - "iterator": "cpp", - "limits": "cpp", - "locale": "cpp", - "memory": "cpp", - "mutex": "cpp", - "new": "cpp", - "optional": "cpp", - "ratio": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "typeinfo": "cpp", - "unordered_map": "cpp", - "utility": "cpp" - } -} \ No newline at end of file diff --git a/Channel.cpp b/Channel.cpp new file mode 100644 index 0000000..2797558 --- /dev/null +++ b/Channel.cpp @@ -0,0 +1,186 @@ +#include "Channel.hpp" + +Channel::Channel() { + name = ""; + topic = ""; + chPassword = ""; + channelType = 0; + hasPassword = 0; +} +Channel::Channel(std::string channelName, int chType) { + name = channelName; + topic = "No topic"; // Default topic value + chPassword = ""; + channelType = chType; + hasPassword = 0; +} + + +Channel::Channel(const Channel ©) { + name = copy.name; + topic = copy.topic; + clients = copy.clients; + operators = copy.operators; + chPassword = copy.chPassword; + channelType = copy.channelType; + hasPassword = copy.hasPassword; +} + +Channel &Channel::operator=(const Channel ©) { + if (this == ©) { + name = copy.name; + topic = copy.topic; + clients = copy.clients; + operators = copy.operators; + chPassword = copy.chPassword; + channelType = copy.channelType; + hasPassword = copy.hasPassword; + } + return *this; +} + +Channel::~Channel() { +} + +void Channel::setName(std::string channelName) { + name = channelName; +} + +// setters and getters : + +void Channel::setTopic(std::string channelTopic) { + topic = channelTopic; +} + +void Channel::setClients(int id, const std::string &userName) { + clients[id].set_nickname(userName); +} + +void Channel::setOperators(int op) { + operators.push_back(op); +} + +void Channel::setChPassword(std::string channelPassword) { + chPassword = channelPassword; +} + +void Channel::setChannelType(int chType) { + channelType = chType; +} + +void Channel::setHasPassword(int hasPsd) { + hasPassword = hasPsd; +} + + + +// void Channel::setInvitedList(int id, client &c){ +// inviteList[id] = c; +// } +std::string Channel::getName() { + return name; +} + +std::string Channel::getTopic() { + return topic; +} + + + +std::vector &Channel::getOperators() { + return operators; +} + +std::string Channel::getChPassword() { + return chPassword; +} + +int Channel::getChannelType() { + return channelType; +} + +// int Channel::getHasPassword() { +// return hasPassword; +// } + +int Channel::getHasPassword() const{ + return hasPassword; +} + + +// std::map Channel::getInvitedList() const{ +// return inviteList; +// } + +std::map::const_iterator Channel::beginClientIter() const { + return clients.begin(); +} + +std::map::const_iterator Channel::endClientIter() const { + return clients.end(); +} + +const std::map &Channel::getClientsFromChannel() const{ + return clients; + +} + +int Channel::getClientID(const std::string &nickname) const { + std::map::const_iterator it; + for (it = clients.begin(); it != clients.end(); ++it) { + if (it->second.getNickname() == nickname) { + return it->first; + } + } + return -1; +} + +int Channel::isClientInChannel(int fd) { + std::map::iterator it; + it = clients.find(fd); + if (it != clients.end()) { + return 1; + } + return 0; +} + +size_t Channel::getClientNb() const { + return clients.size(); +} + +// bool Channel::isClientInvited(int clientId) const{ +// bool isInvited = (inviteList.count(clientId) > 0); +// return isInvited; +// } + +void Channel::removeClient(int fd) { + clients.erase(fd); +} + +void Channel::addOperator(int id) { + operators.push_back(id); +} + +void Channel::removeOperator(int id) { + operators.erase(std::remove(operators.begin(), operators.end(), id), operators.end()); +} + +bool Channel::isOperator(int id) { + return std::find(operators.begin(), operators.end(), id) != operators.end(); +} + +int Channel::getChannelLimit() const { + return channeLimit; +} + +void Channel::setChannelLimit(int limit) { + channeLimit = limit; +} + +void Channel::addInvite(int fd) { + inviteList.push_back(fd); +} + +bool Channel::isClientInvited(int fd) const { + return std::find(inviteList.begin(), inviteList.end(), fd) != inviteList.end(); +} \ No newline at end of file diff --git a/Channel.hpp b/Channel.hpp new file mode 100644 index 0000000..b316aa3 --- /dev/null +++ b/Channel.hpp @@ -0,0 +1,72 @@ +#ifndef CHANNEL_HPP +#define CHANNEL_HPP + +#include +#include +#include +#include +#include "client.hpp" + +class Channel { + private: + std::string name; + std::string topic; + std::string chPassword; + std::vector operators; + std::map clients; + // std::map inviteList; + std::vector inviteList; + int channelType; + int hasPassword; + int channeLimit; + + public: + Channel(); + Channel(std::string channelName, int channelType); + Channel(const Channel ©); + Channel &operator=(const Channel ©); + ~Channel(); + + // setters : + void setName(std::string channelName); + void setTopic(std::string channelTopic); + // void setClients(std::map channelClients); + void setClients(int id, const std::string &userName); + void setOperators(int op); + void setChPassword(std::string channelPassword); + void setChannelType(int channelType); + void setHasPassword(int hasPassword); + // void setInvitedList(int id, client &c); + void setChannelLimit(int limit); + + // getters : + std::string getName(); + std::string getTopic(); + std::vector &getOperators(); + std::string getChPassword(); + std::map::const_iterator beginClientIter() const; + std::map::const_iterator endClientIter() const; + int getChannelLimit() const; + int getChannelType(); + int getClientID(const std::string &nickname) const; + int isClientInChannel(int fd); + int getHasPassword() const; + size_t getClientNb() const; + // std::map getInvitedList() const; + bool isClientInvited(int clientId) const; + const std::map &getClientsFromChannel() const; + + void removeClient(int fd); + void addOperator(int id); + void removeOperator(int id); + bool isOperator(int id); + void addInvite(int fd); + bool isInvited(int fd); + + +}; + + + + +#endif \ No newline at end of file diff --git a/FT_IRC b/FT_IRC deleted file mode 100755 index d269c0a..0000000 Binary files a/FT_IRC and /dev/null differ diff --git a/Makefile b/Makefile index 0ee5865..5d7123c 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,35 @@ -NAME=FT_IRC +# Colors +WHITE = \033[1;37m +RED = \033[1;31m +GREEN = \033[1;32m +YELLOW = \033[1;33m +RESET = \033[0m -CC = c++ -FLAGS = -Wall -Wextra -Werror -std=c++98 -SRC = irc_server.cpp server.cpp client.cpp -OBJ = $(SRC:.cpp=.o) +NAME = ircserv # Change this to your desired executable name +CC = c++ # Change this if your compiler is not g++ +CFLAGS = -Wall -Wextra -Werror -std=c++98 +SRC = irc_server.cpp server.cpp client.cpp cmd.cpp Channel.cpp joinCmd.cpp utils.cpp kickCmd.cpp topicCmd.cpp whoCmd.cpp privmsgCmd.cpp \ + partCmd.cpp modeCmd.cpp nickCmd.cpp quitCmd.cpp inviteCmd.cpp #listCmd.cpp +OBJ = ${SRC:.cpp=.o} -all: $(NAME) +all: ${NAME} -$(NAME): $(OBJ) - $(CC) $(FLAGS) $(OBJ) -o $(NAME) +${OBJ}: %.o: %.cpp + @${CC} ${CFLAGS} -c $< -o $@ -%.o: %.cpp - $(CC) $(FLAGS) -c $< -o $@ +${NAME}: ${OBJ} + @echo "$(YELLOW)Compiling $(NAME)...⏳$(RESET)" + @${CC} ${CFLAGS} -o ${NAME} ${OBJ} + @echo "$(GREEN)Compilation completed ✅$(RESET)" clean: - rm -f $(OBJ) + @${RM} ${OBJ} + @echo "$(RED)Obj_files removed.$(RESET)" fclean: clean - rm -f $(NAME) + @${RM} ${NAME} + @echo "$(RED)Executable removed.$(RESET)" -re: fclean all \ No newline at end of file +re: fclean all + +.PHONY: all clean fclean re diff --git a/README.md b/README.md deleted file mode 100644 index e3e9f92..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# FT_IRC diff --git a/client.cpp b/client.cpp index 9866f9e..1f35e44 100644 --- a/client.cpp +++ b/client.cpp @@ -1,4 +1,15 @@ #include "client.hpp" +#include "utils.hpp" + +std::vector client::fds; +std::vector client::clients; + +client::client() +{ + this->is_authenticated = false; + this->is_registered = false; + this->index = 0; +} client::client(pollfd client_pfd, std::string password) { @@ -6,9 +17,9 @@ client::client(pollfd client_pfd, std::string password) this->is_authenticated = false; this->is_registered = false; this->password = password; + this->index = 0; } - client::~client() { // std::cout << "client with nickname " << this->nickname << " is destroyed" << std::endl; @@ -30,40 +41,128 @@ void client::set_realname(std::string realname) this->realname = realname; } -bool client::set_authenticated() +std::string client::getNickname() const { + return this->nickname; +} + +std::string client::getUsername()const +{ + return this->username; +} + +std::vector buffer_to_line(std::string buffer, std::string siparator) +{ + std::vector lines; std::string line; - if (this->is_registered == true) - { - return (true); - }else + std::istringstream stm(buffer); + while (std::getline(stm, line)) { - if (this->massage.find("NICK") != std::string::npos) + size_t found = line.find_first_of(siparator); + + if (found != std::string::npos) { - line = this->massage.substr(this->massage.find("NICK"), this->massage.find("\n")); - this->nickname = line.substr(5, line.find("\n")); + line = line.substr(0, found); + lines.push_back(line); } - if (this->massage.find("USER") != std::string::npos) + + } + return lines; +} + + bool client::check_nickname(std::string nickname, std::vector& clients) +{ + std::vector::iterator it = clients.begin(); + while (it != clients.end()) + { + + if (it->getNickname() == nickname && it->is_authenticated == true) { - line = this->massage.substr(this->massage.find("USER"), this->massage.find("\n")); - this->username = line.substr(5, line.find("\n")); + + return (false); } - if (this->massage.find("REALNAME") != std::string::npos) + it++; + } + return (true); +} + +bool client::set_authenticated(std::vector clients) +{ + std::string line; + if (this->is_authenticated == true) + { + return (true); + } + else { + std::vector lines; + if (this->massage.find("\r\n") != std::string::npos) { - line = this->massage.substr(this->massage.find("REALNAME"), this->massage.find("\n")); - this->realname = line.substr(9, line.find("\n")); + lines = buffer_to_line(this->massage, "\r\n"); } - if (this->nickname != "" && this->username != "" && this->realname != "") + + if (this->massage.find("\r") != std::string::npos && this->massage.find("\r\n") == std::string::npos ) { - this->is_registered = true; - return (true); - }else + lines = buffer_to_line(this->massage, "\n"); + } + + for (unsigned int i = 0; i < lines.size(); i++) { - return (false); + if (lines[i].find("NICK") != std::string::npos) + { + std::string nickname = lines[i].substr(5, lines[i].size()); + + std::string tmp_nickname = nickname; + + if (check_nickname(nickname, clients) == false) + { + std::string message = "433 :nickname is already in use\r\n"; + sendMessage(this->client_pfd.fd, message); + return (false); + } + this->set_nickname(nickname); + } + if (lines[i].find("USER") != std::string::npos) + { + std::string username = lines[i].substr(5, lines[i].size()); + this->set_username(username); + + + // try to grt the hodt name { this->username = user_abdel-ou user_abdel-ou localhost :realname} try to get the host name + + size_t found1 = this->username.find(" "); + if (found1 != std::string::npos) { + size_t found2 = this->username.find(" ", found1 + 1); + if (found2 != std::string::npos) { + + std::string tmp_realname = this->username.substr(found2 + 1, this->username.size()); + + size_t found3 = tmp_realname.find(" "); + if (found3 != std::string::npos) { + std::string realname = tmp_realname.substr(0, found3); + this->hostname = realname; + } + } + } + } + + if (lines[i].find("PASS") != std::string::npos) + { + this->sabmit_password = lines[i].substr(5, lines[i].size()); + } } - + // check if the password is incorrect + if ((this->sabmit_password.size() > 0 ) && (lines.size() > 3) && (this->password != this->sabmit_password)) + { + std::string message = "464 :password incorrect\r\n"; + sendMessage(this->client_pfd.fd, message); + return (false); + } + if ((this->nickname.size() > 0) && (this->username.size() > 0) && (this->password == this->sabmit_password)) + { + this->is_authenticated = true; + return (true); + } } - return (false); } @@ -72,7 +171,7 @@ void client::set_registered(bool is_registered) this->is_registered = is_registered; } -pollfd client::get_client_pfd() +pollfd client::get_client_pfd() const { return this->client_pfd; } @@ -82,19 +181,67 @@ void client::set_client_pfd(pollfd client_pfd) this->client_pfd = client_pfd; } +void client::set_massage_for_auth(std::string massage) +{ + this->massage = this->massage + massage; +} +// get message +std::string client::get_message() +{ + return this->massage; +} +void client::print_massage() +{ + this->index++; + std::cout << "--------------" << "the cleint " << this->client_pfd.fd << " : " << this->index << " : print massage method start ----------------" << std::endl; + std::cout << this->massage; + std::cout << "--------------print massage method end----------------" << std::endl; +} +void client::print_client() +{ + std::cout << "nickname : " << this->nickname << std::endl; + std::cout << "username : " << this->username << std::endl; + std::cout << "realname : " << this->realname << std::endl; + std::cout << "password sabmited : " << this->sabmit_password << std::endl; + std::cout << "password : " << this->password << std::endl; +} + + +void client::clear_massage() +{ + this->massage = ""; +} void client::set_massage(std::string massage) { - this->massage = this->massage + massage; + this->massage = massage; } -void client::print_massage() + +std::string client::get_host_name() { - std::cout << this->massage << std::endl; + return this->hostname; } +int client::getFd() const +{ + return this->client_pfd.fd; +} + +void client::modify_client(int fd, const std::string& newNickname) +{ + std::vector& clients = client::get_clients(); + for (std::vector::iterator it = clients.begin(); it != clients.end(); ++it) { + if (it->getFd() == fd) { + it->set_nickname(newNickname); + return; + } + } +} +std::vector& client::get_fds() { return fds; } +std::vector& client::get_clients() { return clients; } diff --git a/client.hpp b/client.hpp index 1791310..1157643 100644 --- a/client.hpp +++ b/client.hpp @@ -3,7 +3,8 @@ #include #include - +#include +#include class client { private : @@ -12,28 +13,47 @@ class client std::string nickname; std::string username; std::string realname; + std::string hostname; std::string password; + std::string sabmit_password; bool is_authenticated; bool is_registered; std::string massage; + int index; + static std::vector fds; + static std::vector clients; public : + client(); client(pollfd client_pfd, std::string password); ~client(); - void set_nickname(std::string nickname); - void set_username(std::string username); - void set_realname(std::string realname); - bool set_authenticated(); - void set_registered(bool is_registered); - pollfd get_client_pfd(); - void set_client_pfd(pollfd client_pfd); - void set_massage(std::string massage); - void print_massage(); -}; + pollfd get_client_pfd() const; + std::string getNickname() const; + std::string getUsername() const; + std::string get_message(); + void set_nickname(std::string nickname); + void set_username(std::string username); + void set_realname(std::string realname); + bool set_authenticated(std::vector); + void set_registered(bool is_registered); + void set_client_pfd(pollfd client_pfd); + void set_massage_for_auth(std::string massage); + void set_massage(std::string massage); + void print_massage(); + void print_client(); + void clear_massage(); + static std::vector& get_fds(); + static std::vector& get_clients(); + std::string get_host_name(); + int getFd() const; + static void modify_client(int fd, const std::string& newNickname); + bool check_nickname(std::string nickname, std::vector& clients); +}; -#endif +std::vector buffer_to_line(std::string buffer); +#endif \ No newline at end of file diff --git a/client.o b/client.o deleted file mode 100644 index 5af685a..0000000 Binary files a/client.o and /dev/null differ diff --git a/cmd.cpp b/cmd.cpp new file mode 100644 index 0000000..8311727 --- /dev/null +++ b/cmd.cpp @@ -0,0 +1,53 @@ +#include "server.hpp" +#include "Channel.hpp" +#include "client.hpp" +#include "utils.hpp" +#include +#include +#include +#include +#include + +void Server::command(int fd) { + std::string line = getClientMessage(fd); + std::istringstream stream(line); + std::string command; + std::vector res; + + stream >> command; + std::transform(command.begin(), command.end(), command.begin(), ::tolower); + + std::string arg; + while (stream >> arg) { + res.push_back(arg); + } + // int size = res.size(); + // std::cout << "size of res is : " << size << std::endl; + // for (int i = 0; i < size; i++) { + // std::cout << "res[" << i << "] = " << res[i] << std::endl; + // } + if (command.compare("join") == 0) + joinCmd(res, fd); + else if (command.compare("kick") == 0) + kickCmd(res, fd); + else if (command.compare("topic") == 0) + topicCmd(res, fd); + else if (command.compare("who") == 0) + whoCmd(res, fd); + else if (command.compare("part") == 0) + partCmd(res, fd); + else if (command.compare("privmsg") == 0) + privmsgCmd(res, fd); + else if (command.compare("nick") == 0) + nickCmd(res, fd); + else if (command.compare("mode") == 0) + modeCmd(res, fd); + else if (command.compare("invite") == 0) + inviteCmd(res, fd); + else if (command.compare("quit") == 0) + quitCmd(res, fd); + else { + std::string msg = "421 " + getClientNickname(fd) + " " + command + " :Unknown command\n"; + sendMessage(fd, msg); + } +} diff --git a/inviteCmd.cpp b/inviteCmd.cpp new file mode 100644 index 0000000..cfee0b4 --- /dev/null +++ b/inviteCmd.cpp @@ -0,0 +1,44 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::inviteCmd(std::vector& args, int fd) { + if (args.size() < 2) { + std::string msg = ":" + getClientHostName(fd) + " 461 " + getClientNickname(fd) + " INVITE :Not enough parameters\r\n"; + sendMessage(fd, msg); + return; + } + + const std::string& nickname = args[0]; + const std::string& channelName = args[1]; + + std::map::iterator it = channels.find(channelName); + + if (it == channels.end()) { + std::string msg = ":" + getClientHostName(fd) + " 403 " + getClientNickname(fd) + " " + channelName + " :No such channel\r\n"; + sendMessage(fd, msg); + } else { + Channel& channel = it->second; + if (!channel.isClientInChannel(fd)) { + std::string msg = ":" + getClientHostName(fd) + " 442 " + getClientNickname(fd) + " " + channelName + " :You're not on that channel\r\n"; + sendMessage(fd, msg); + } else { + int clientFd = getClientFdByNickname(nickname); + if (clientFd == -1) { + std::string msg = ":" + getClientHostName(fd) + " 401 " + getClientNickname(fd) + " " + nickname + " :No such nick/channel\r\n"; + sendMessage(fd, msg); + } else { + // Add the client to the invite list + channel.addInvite(clientFd); + + std::string msg = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " INVITE " + nickname + " :" + channelName + "\r\n"; + sendMessage(clientFd, msg); + std::string msg2 = ":" + getClientHostName(fd) + " 341 " + getClientNickname(fd) + " " + nickname + " " + channelName + "\r\n"; + sendMessage(fd, msg2); + } + } + } +} \ No newline at end of file diff --git a/irc_server.cpp b/irc_server.cpp index 174f96a..2901437 100644 --- a/irc_server.cpp +++ b/irc_server.cpp @@ -1,119 +1,102 @@ #include "irc_server.hpp" #include "server.hpp" #include "client.hpp" - +#include // for std::transform int main(int argc, char *argv[]) { - if(argc != 3) + // check if the size of the last arg is not equal to 0 + if (argc != 3 || strlen(argv[2]) == 0 || strlen(argv[1]) == 0) { std::cout << "Usage: ./irc_server " << std::endl; return (1); } -Server irc_server("0.0.0.0", argv[1]); -irc_server.setsockopt(); -irc_server.bind_socket(); -irc_server.listen_socket(); - - - -std::vector fds; + Server irc_server("0.0.0.0", argv[1]); + irc_server.setsockopt(); + irc_server.bind_socket(); + irc_server.listen_socket(); -std::vector clients; + client::get_fds() = irc_server.get_fds(); -fds = irc_server.get_fds(); - -// std::cout << "server is running :: fds : " << fds.front().fd << std::endl; - -while (1) -{ - int r = poll(&fds[0], fds.size(), -1); - if (r == -1) + while (1) { - std::cout << "error in poll function" << std::endl; - } - unsigned int i = 0; - while ( i < fds.size()) - { - - if (fds[i].revents & POLLIN) + int r = poll(&client::get_fds()[0], client::get_fds().size(), -1); + if (r == -1) + { + std::cout << "error in poll function" << std::endl; + } + unsigned int i = 0; + while (i < client::get_fds().size()) { - if (fds[i].fd == irc_server.get_sockfd()) + if (client::get_fds()[i].revents & POLLIN) { - // New client - sockaddr_in clientaddr; - socklen_t client_len = sizeof(clientaddr); - int clientfd = accept(irc_server.get_sockfd(), (struct sockaddr*)&clientaddr, &client_len); - - if (clientfd == -1) + if (client::get_fds()[i].fd == irc_server.get_sockfd()) { - std::cout << "error in accept function" << std::endl; + // New client + sockaddr_in clientaddr; + socklen_t client_len = sizeof(clientaddr); + int clientfd = accept(irc_server.get_sockfd(), (struct sockaddr*)&clientaddr, &client_len); + + if (clientfd == -1) + { + std::cout << "error in accept function" << std::endl; + } + else + { + // std::cout << "new client connected " << inet_ntoa(clientaddr.sin_addr) << std::endl; + pollfd client_pfd; + + client_pfd.fd = clientfd; + client_pfd.events = POLLIN; + client::get_fds().push_back(client_pfd); + + client::get_clients().push_back(client(client_pfd, argv[2])); + } } else { - // std::cout << "new client connected " << inet_ntoa(clientaddr.sin_addr) << std::endl; - pollfd client_pfd; - - client_pfd.fd = clientfd; - client_pfd.events = POLLIN; - fds.push_back(client_pfd); - - clients.push_back(client(client_pfd, argv[2])); - } - } - else - { - - char buffer[1024]; - int r = recv(fds[i].fd, buffer, sizeof(buffer), 0); - if (r > 0) - { - buffer[r] = '\0'; - - // std::cout << buffer; - unsigned int l = 0; - while (l < clients.size()) + char buffer[1024]; + int r = recv(client::get_fds()[i].fd, buffer, sizeof(buffer), 0); + if (r > 0) { - if ((clients[l].get_client_pfd().fd == fds[i].fd)) + buffer[r] = '\0'; + + // std::cout << buffer; + unsigned int l = 0; + while (l < client::get_clients().size()) { - if (clients[l].set_authenticated() == true) - { - std::cout << "client : " << l << " authenticated" << std::endl; - } - - if (buffer[0] != ':') - { - // std::cout << "client found" << std::endl; - clients[l].set_massage(buffer); - buffer[0] = '\0'; - }else + if (client::get_clients()[l].get_client_pfd().fd == client::get_fds()[i].fd) { - std::cout << "---------------------------------" << std::endl; - std::cout << "client : " << l << std::endl; - clients[l].print_massage(); - std::cout << "---------------------------------" << std::endl; + if (client::get_clients()[l].set_authenticated(client::get_clients()) == true) + { + client::get_clients()[l].set_massage(buffer); + // print host name + // std::cout << client::get_clients()[l].get_host_name() << std::endl; + // work will be done here + irc_server.command(client::get_fds()[i].fd); + // print the client name and message + std::cout << "we are receiving message from authenticated client: " << client::get_clients()[l].get_message() << std::endl; + } + else + { + client::get_clients()[l].set_massage_for_auth(buffer); + // std::cout << client::get_clients()[l].get_client_pfd().fd << " is not authenticated" << std::endl; + if (client::get_clients()[l].set_authenticated(client::get_clients()) == true) + { + std::cout << "Now is authenticated" << std::endl; + client::get_clients()[l].clear_massage(); + std::cout << client::get_clients()[l].get_message() << std::endl; + } + } } + l++; } - - - l++; } - // unsigned int j = 0; - // while ( j < fds.size()) - // { - // if(fds[j].fd != irc_server.get_sockfd()) - // { - // send(fds[j].fd, buffer, r, 0); - // } - // j++; - // } } } + i++; } - i++; } -} - -return (0); + return (0); } diff --git a/irc_server.o b/irc_server.o deleted file mode 100644 index c1a9abd..0000000 Binary files a/irc_server.o and /dev/null differ diff --git a/joinCmd.cpp b/joinCmd.cpp new file mode 100644 index 0000000..f2fc568 --- /dev/null +++ b/joinCmd.cpp @@ -0,0 +1,139 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::setupChannel(const std::string &channelName, int fd, const std::string &password) { + if (channels.find(channelName) == channels.end()) { + Channel newChannel(channelName, 0); + channels[channelName] = newChannel; + } else { + // Ensure not to reset the topic if the channel already exists + Channel &channel = channels[channelName]; + if (channel.getTopic() == "No topic") { + channel.setTopic("No topic"); + } + } + + // Additional setup code + Channel &channel = channels[channelName]; + channel.setClients(fd, getClientNickname(fd)); + if (password.empty()) { + channel.setChannelType(0); // Public + channel.setHasPassword(0); + } else { + channel.setChannelType(1); // Password protected + channel.setHasPassword(1); + channel.setChPassword(password); + } +} + +void Server::JoinMessage(int fd, const std::string &channelName) { + + std::map::iterator it = channels.find(channelName); + + if (channels.find(channelName) != channels.end()) { + std::string globmsg = ""; + std::string topic = channels[channelName].getTopic(); // Get topic + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " JOIN " + channelName + " * :realname\r\n"; + globmsg += message; + + Channel& channel = it->second; + std::string message2 = ":" + getClientHostName(fd) + " 353 " + getClientNickname(fd) + " = " + channelName + " :"; + bool first = true; + + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (!first) { + message2 += " "; + } + first = false; + // :luna.AfterNET.Org 353 simo = #chan :simo!dd@88ABE6.25BF1D.D03F86.88C9BD.IP @bello!dd@88ABE6.25BF1D.D03F86.88C9BD.I + // if the client is an operator + if (channel.isOperator(clientIt->first)) { + message2 += "@" + clientIt->second.getNickname() + "!" + clientIt->second.getNickname() + "@" + getClientHostName(clientIt->first); + } else { + message2 += clientIt->second.getNickname() + "!" + clientIt->second.getNickname() + "@" + getClientHostName(clientIt->first); + } + } + message2 += "\n"; + globmsg += message2; + + std::string message3 = ":" + getClientHostName(fd) + " 366 " + getClientNickname(fd) + " " + channelName + " :End of /NAMES list.\r\n"; + globmsg += message3; + + // send to other clients in the channel like this message :simo!simo@88ABE6.25BF1D.D03F86.88C9BD.IP JOIN #chan * :realname + for (std::map::const_iterator it = channel.beginClientIter(); it != channel.endClientIter(); ++it) { + if (it->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " JOIN " + channelName + " * :realname\r\n"; + sendMessage(it->first, message); + } + } + sendMessage(fd, globmsg); + } else { + std::string globmsg = ":" + getNameId(fd) + " 403 " + channelName + " :No such channel\n"; + sendMessage(fd, globmsg); + } +} + +void Server::joinCmd(std::vector ¶m, int fd) { + if (param.empty() || param[0][0] != '#' || param[0].size() <= 1) { + std::string message = ":" + getNameId(fd) + " 461 JOIN :Not enough parameters\n"; + sendMessage(fd, message); + return; + } + + std::string channelName = param[0]; + std::string password = (param.size() > 1) ? param[1] : ""; + + std::map::iterator it = channels.find(channelName); + bool channelCreated = (it == channels.end()); + + if (channelCreated) { + // Create the channel if it doesn't exist + setupChannel(channelName, fd, (param.size() == 2) ? param[1] : ""); + // add the client to the operator list + channels[channelName].addOperator(fd); + JoinMessage(fd, channelName); + } + else { + std::cout << "Channel \"" << channelName << "\" already exists \""<< std::endl; + // std::cout << "client name is : " << getClientNickname(fd) << std::endl; + // std::cout << "channel name is : " << channelName << std::endl; + + // Get reference to the existing channel + Channel &channel = channels[channelName]; + + // Check if the channel is invite-only and if the client is invited + if (channel.getChannelType() & 2) { // Check for invite-only flag + if (!channel.isClientInvited(fd)) { + std::string message = ":" + getNameId(fd) + " 473 " + channelName + " :Cannot join channel (+i)\n"; + sendMessage(fd, message); + return; + } + } + + // Check if the channel has a password and if the provided password is correct + if (channel.getChPassword() != password) { + std::string message = ":" + getNameId(fd) + " 475 " + channelName + " :Cannot join channel (+k) - incorrect key\n"; + sendMessage(fd, message); + return; + } + + // Check if the channel has a user limit and if the limit is reached + if (channel.getChannelLimit() > 0 && channel.getClientsFromChannel().size() >= static_cast(channel.getChannelLimit())) { + std::string message = ":" + getNameId(fd) + " 471 " + channelName + " :Cannot join channel (+l) - channel is full\n"; + sendMessage(fd, message); + return; + } + + // Add the client to the channel + channel.setClients(fd, getClientNickname(fd)); + + // Inform the client about joining the channel + JoinMessage(fd, channelName); + } +} diff --git a/kickCmd.cpp b/kickCmd.cpp new file mode 100644 index 0000000..f669f49 --- /dev/null +++ b/kickCmd.cpp @@ -0,0 +1,55 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::kickCmd(std::vector& args, int fd) { + if (args.size() <= 2) { + std::string msg = "461 " + getClientNickname(fd) + " KICK :Not enough parameters\n"; + sendMessage(fd, msg); + return; + } + + const std::string& channelName = args[1]; + std::string userToKick = args[2]; + if (userToKick[0] == ':') { + userToKick = userToKick.substr(1); + } + + std::map::iterator it = channels.find(channelName); + if (it == channels.end()) { + std::string msg = "403 " + getClientNickname(fd) + " " + channelName + " :No such channel\n\r"; + sendMessage(fd, msg); + return; + } + + Channel& channel = it->second; + int fdToKick = channel.getClientID(userToKick); + if (fdToKick == -1) { + std::string msg = "401 " + getClientNickname(fd) + " " + userToKick + " :No such nick/channel\n\r"; + sendMessage(fd, msg); + return; + } + + if (!channel.isClientInChannel(fdToKick)) { + std::string msg = "441 " + getClientNickname(fd) + " " + userToKick + " " + channelName + " :They aren't on that channel\n\r"; + sendMessage(fd, msg); + return; + } + else { + std::cout << "Kicking user \"" << userToKick << "\" is on the channel \"" << channelName + "\"" << std::endl; + } + + channel.removeClient(fdToKick); + + + std::string msg = ":" + getClientNickname(fd) + " KICK " + channelName + " " + userToKick + " :" + getClientNickname(fd) + "\n\r"; + sendMessage(fd, msg); + + // Send the message to the client being kicked + std::string kickMsg = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " KICK " + channelName + " " + userToKick + " :" + getClientNickname(fd) + "\n\r"; + sendMessage(fdToKick, kickMsg); + +} \ No newline at end of file diff --git a/modeCmd.cpp b/modeCmd.cpp new file mode 100644 index 0000000..14e7198 --- /dev/null +++ b/modeCmd.cpp @@ -0,0 +1,261 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::modeCmd(std::vector ¶m, int fd) { + std::cout << "size: " << param.size() << std::endl; + if (param.size() == 1) { + std::string message = ":" + getClientHostName(fd) + " 324 " + getClientNickname(fd) + " " + param[0] + " +tn\r\n"; + sendMessage(fd, message); + return; + } + + const std::string& channelName = param[0]; + std::map::iterator it = channels.find(channelName); + + if (it == channels.end()) { + std::string message = ":" + getClientHostName(fd) + " 403 " + getClientNickname(fd) + " " + channelName + " :No such channel\n"; + sendMessage(fd, message); + return; + } + + Channel& channel = it->second; + if (!channel.isClientInChannel(fd)) { + std::string message = ":" + getClientHostName(fd) + " 442 " + getClientNickname(fd) + " " + channelName + " :You're not on that channel\n"; + sendMessage(fd, message); + return; + } + + // Check if the client is an operator + const std::vector& operators = channel.getOperators(); + bool isOperator = false; + for (std::vector::const_iterator itOp = operators.begin(); itOp != operators.end(); ++itOp) { + if (*itOp == fd) { + isOperator = true; + break; + } + } + // // print operators + // std::vector ops = channel.getOperators(); + // for (size_t i = 0; i < ops.size(); i++) { + // // print operator's nickname + // std::cout << "Operator: " << getClientNickname(ops[i]) << std::endl; + // } + // :luna.AfterNET.Org 482 simo #chan :You're not channel operat + if (!isOperator) { + std::string message = ":" + getClientHostName(fd) + " 482 " + getClientNickname(fd) + " " + channelName + " :You're not channel operator\r\n"; + sendMessage(fd, message); + return; + } + + //print param + for (size_t i = 0; i < param.size(); i++) { + std::cout << "param[" << i << "]: " << param[i] << std::endl; + } + + // Process mode changes + std::string modeChanges = param[1]; + std::vector targets; + if (param.size() > 2) { + targets = split(param[2], ','); // Split all clients to be affected by the mode change + } + + // the MODE command is started here + bool addingMode = true; + for (std::string::size_type i = 0; i < modeChanges.size(); ++i) { + char mode = modeChanges[i]; + if (mode == '+') { + addingMode = true; + continue; + } else if (mode == '-') { + addingMode = false; + continue; + } + // std::cout << "mode: " << mode << std::endl; + switch (mode) { + case 'i': { + if (addingMode) { + channel.setChannelType(channel.getChannelType() | 2); // Set to invite-only + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +i\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +i\r\n"; + sendMessage(clientIt->first, message); + } + } + } else { + channel.setChannelType(channel.getChannelType() & ~2); // Remove invite-only + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -i\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -i\r\n"; + sendMessage(clientIt->first, message); + } + } + } + break; + } + case 't': { + if (addingMode) { + channel.setChannelType(channel.getChannelType() | 4); // Set topic restriction + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +t\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +t\r\n"; + sendMessage(clientIt->first, message); + } + } + } else { + channel.setChannelType(channel.getChannelType() & ~4); // Remove topic restriction + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -t\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -t\r\n"; + sendMessage(clientIt->first, message); + } + } + } + break; + } + case 'k': { + if (addingMode && targets.empty()) { + std::string message = ":" + getClientHostName(fd) + " 461 " + getClientNickname(fd) + " MODE :Not enough parameters\n"; + sendMessage(fd, message); + return; + } else if (addingMode) { + channel.setChPassword(targets[0]); + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +k " + targets[0] + "\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +k " + targets[0] + "\r\n"; + sendMessage(clientIt->first, message); + } + } + } else { + channel.setChPassword(""); + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -k\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -k\r\n"; + sendMessage(clientIt->first, message); + } + } + } + } + case 'o': { + for (std::vector::size_type j = 0; j < targets.size(); ++j) { + const std::string &target = targets[j]; + int clientId = channel.getClientID(target); + if (clientId != -1) { + if (addingMode) { + channel.addOperator(clientId); + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +o " + target + "\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +o " + target + "\r\n"; + sendMessage(clientIt->first, message); + } + } + } else { + channel.removeOperator(clientId); + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -o " + target + "\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -o " + target + "\r\n"; + sendMessage(clientIt->first, message); + } + } + } + } + } + break; + } + case 'l': { + if (addingMode) { + if (targets.empty()) { + std::string message = ":" + getClientHostName(fd) + " 461 " + getClientNickname(fd) + " MODE :Not enough parameters\n"; + sendMessage(fd, message); + return; + } + int limit = std::stoi(targets[0]); + channel.setChannelLimit(limit); + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +l " + targets[0] + "\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " +l " + targets[0] + "\r\n"; + sendMessage(clientIt->first, message); + } + } + } else { + channel.setChannelLimit(0); + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -l\r\n"; + sendMessage(fd, message); + + // notify other clients + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + std::string message = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " MODE " + channelName + " -l\r\n"; + sendMessage(clientIt->first, message); + } + } + } + break; + } + default: { + std::string message = "472 " + getClientNickname(fd) + " " + channelName + " " + mode + " :is unknown mode char to me\n"; + sendMessage(fd, message); + break; + } + } + } +} diff --git a/nickCmd.cpp b/nickCmd.cpp new file mode 100644 index 0000000..befd386 --- /dev/null +++ b/nickCmd.cpp @@ -0,0 +1,51 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::nickCmd(std::vector& args, int fd) { + if (args.size() == 0) { + std::string msg = "431 " + getClientNickname(fd) + " :No nickname given\n\r"; + sendMessage(fd, msg); + return; + } + + const std::string& newNickname = args[0]; + + std::cout << "New nickname: " << newNickname << std::endl; + + // Check if the nickname is already in use + const std::vector& clients = client::get_clients(); + for (std::vector::const_iterator it = clients.begin(); it != clients.end(); ++it) { + if (it->getNickname() == newNickname) { + std::string msg = "433 " + newNickname + " :Nickname is already in use\n\r"; + sendMessage(fd, msg); + return; + } + } + + // print the name of the client before changing it + std::string oldNickname = getClientNickname(fd); + std::cout << "Fd: " << fd << " old nickname: " << oldNickname << std::endl; + + // Modify the client's nickname + client::modify_client(fd, newNickname); + + // print the name of the client after changing it + std::cout << "Fd: " << fd << " new nickname: " << getClientNickname(fd) << std::endl; + + // Notify other clients about the nickname change + std::string notice = ":" + oldNickname + "!" + oldNickname + "@" + getClientHostName(fd) + " NICK :" + newNickname + "\n\r"; + for (std::vector::const_iterator it = clients.begin(); it != clients.end(); ++it) { + if (it->getFd() != fd) { + sendMessage(it->getFd(), notice); + } + } + + // // Confirm the change to the client + // :bello!bik@88ABE6.25BF1D.D03F86.88C9BD.IP NICK :bik + std::string msg = ":" + oldNickname + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " NICK :" + getClientNickname(fd) + "\n\r"; + sendMessage(fd, msg); +} diff --git a/partCmd.cpp b/partCmd.cpp new file mode 100644 index 0000000..b2b8b1a --- /dev/null +++ b/partCmd.cpp @@ -0,0 +1,42 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::partCmd(std::vector& args, int fd) { + if (args.size() == 0) { + std::string msg = "461 " + getClientNickname(fd) + " PART :Not enough parameters\n"; + sendMessage(fd, msg); + return; + } + + const std::string& channelName = args[0]; + std::map::iterator it = channels.find(channelName); + if (it == channels.end()) { + std::string msg = "403 " + getClientNickname(fd) + " " + channelName + " :No such channel\n"; + sendMessage(fd, msg); + return; + } + + Channel& channel = it->second; + if (!channel.isClientInChannel(fd)) { + std::string msg = "442 " + getClientNickname(fd) + " " + channelName + " :You're not on that channel\n"; + sendMessage(fd, msg); + return; + } + + channel.removeClient(fd); + // :simo!simo@88ABE6.25BF1D.D03F86.88C9BD.IP PART #chan :Leaving + std::string msg = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " PART " + channelName + " :Leaving\n"; + + // Send the message to all clients in the channel + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + sendMessage(clientIt->first, msg); + } + + sendMessage(fd, msg); +} \ No newline at end of file diff --git a/privmsgCmd.cpp b/privmsgCmd.cpp new file mode 100644 index 0000000..7b54d1f --- /dev/null +++ b/privmsgCmd.cpp @@ -0,0 +1,70 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::privmsgCmd(std::vector& args, int fd) { + + if (args.size() < 1) { + std::string msg = "411 " + getClientNickname(fd) + " :No recipient given (PRIVMSG)\n\r"; + sendMessage(fd, msg); + return; + } + else if (args.size() == 1) { + std::string msg = "412 " + getClientNickname(fd) + " :No text to send\n\r"; + sendMessage(fd, msg); + return; + } + + const std::string& recipient = args[0]; + std::string message = args[1]; + for (size_t i = 2; i < args.size(); ++i) { + message += " " + args[i]; + } + + std::vector& clients = client::get_clients(); + bool recipientFound = false; + client* recipientClient = nullptr; + + // Check if the recipient is a client + for (std::vector::iterator it = clients.begin(); it != clients.end(); ++it) { + if (it->getNickname() == recipient) { + recipientClient = &(*it); // Point to the recipient client + recipientFound = true; + break; + } + } + + if (!recipientFound) { + // Recipient not found as a client + std::map::iterator channelIt = channels.find(recipient); + + if (channelIt == channels.end()) { + std::string msg = "401 " + getClientNickname(fd) + " " + recipient + " :No such nick/channel\n\r"; + sendMessage(fd, msg); + } + else { + std::cout << "Channel found" << std::endl; + Channel& channel = channelIt->second; + std::string msg = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " PRIVMSG " + recipient + " :" + message + "\n\r"; + for (std::map::const_iterator it = channel.beginClientIter(); it != channel.endClientIter(); ++it) { + if (it->first != fd) { + sendMessage(it->first, msg); + } + } + } + } + else { + std::string msg; + if (message[0] == ':') { + std::cout << "Message starts with :" << std::endl; + msg = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " PRIVMSG " + recipient + " " + message + "\n\r"; + } else { + std::cout << "Message does not start with :" << std::endl; + msg = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " PRIVMSG " + recipient + " :" + message + "\n\r"; + } + sendMessage(recipientClient->get_client_pfd().fd, msg); + } +} diff --git a/quitCmd.cpp b/quitCmd.cpp new file mode 100644 index 0000000..6c0ce4c --- /dev/null +++ b/quitCmd.cpp @@ -0,0 +1,37 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::quitCmd(std::vector& args, int fd) { + if (args.size() == 0) { + // erase client from clients vector + std::vector& clients = client::get_clients(); // remove const to allow modification + for (std::vector::iterator it = clients.begin(); it != clients.end(); ) { + if (it->getFd() == fd) { + it = clients.erase(it); + } else { + ++it; // only increment if not erased + } + } + std::string msg = "QUIT :Leaving\n"; + sendMessage(fd, msg); + return; + } + + std::vector& clients = client::get_clients(); // remove const to allow modification + std::string notice = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " QUIT :Quit: " + args[0] + "\n"; + for (std::vector::iterator it = clients.begin(); it != clients.end(); ) { + if (it->getFd() == fd) { + it = clients.erase(it); + } else { + sendMessage(it->getFd(), notice); + ++it; // only increment if not erased + } + } + + std::string msg = "QUIT :" + args[0] + "\n"; + sendMessage(fd, msg); +} \ No newline at end of file diff --git a/server.cpp b/server.cpp index 1c349ab..241cfcb 100644 --- a/server.cpp +++ b/server.cpp @@ -1,4 +1,5 @@ #include "server.hpp" +#include "utils.hpp" Server::Server(std::string ip, std::string port) { @@ -69,4 +70,42 @@ int Server::get_sockfd() std::vector Server::get_fds() { return this->fds; -} \ No newline at end of file +} + +std::string Server::getClientNickname(int fd) { + std::vector& clients = client::get_clients(); + std::vector::iterator it = std::find_if(clients.begin(), clients.end(), IsClientWithFd(fd)); + return (it != clients.end()) ? it->getNickname() : "Unknown"; +} + +std::string Server::getClientMessage(int fd) { + std::vector& clients = client::get_clients(); + std::vector::iterator it = std::find_if(clients.begin(), clients.end(), IsClientWithFd(fd)); + return (it != clients.end()) ? it->get_message() : ""; +} + +std::string Server::getClientHostName(int fd) { + std::vector& clients = client::get_clients(); + std::vector::iterator it = std::find_if(clients.begin(), clients.end(), IsClientWithFd(fd)); + return (it != clients.end()) ? it->get_host_name() : ""; +} + +std::string Server::getNameId(int fd) { + std::vector& clients = client::get_clients(); + for (std::vector::iterator it = clients.begin(); it != clients.end(); ++it) { + if (it->get_client_pfd().fd == fd) { + return it->getNickname(); + } + } + return "ERROR"; +} + +int Server::getClientFdByNickname(const std::string& nickname) { + std::vector& clients = client::get_clients(); + for (std::vector::iterator it = clients.begin(); it != clients.end(); ++it) { + if (it->getNickname() == nickname) { + return it->get_client_pfd().fd; + } + } + return -1; // Return -1 if no client with the given nickname is found +} diff --git a/server.hpp b/server.hpp index 1318b6e..7db59dd 100644 --- a/server.hpp +++ b/server.hpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include "client.hpp" +#include "Channel.hpp" class Server { @@ -15,6 +18,10 @@ class Server int sockfd; struct addrinfo hints, *server; std::vector fds; + std::map channels; + std::map clients; + // std::map _clients; + public : Server(std::string ip, std::string port); void bind_socket(); @@ -24,7 +31,34 @@ class Server int get_sockfd(); ~Server(); - -}; -#endif + void joinCmd(std::vector ¶m, int fd); + void privmsgCmd(std::vector& args, int fd); + void modeCmd(std::vector ¶m, int fd); + void whoCmd(std::vector& args, int fd); + void kickCmd(std::vector ¶m, int fd); + void nickCmd(std::vector ¶m, int fd); + void topicCmd(std::vector ¶m, int fd); + void partCmd(std::vector& args, int fd); + void inviteCmd(std::vector& args, int fd); + void quitCmd(std::vector& args, int fd); + int getClientFdByNickname(const std::string& nickname); + std::string getNameId(int fd); + void joinMessage(int fd, const std::string &channelName); + void setupChannel(const std::string &channelName, int fd, const std::string &password); + void JoinMessage(int fd, const std::string &channelName); + void command(int fd); + std::string getClientMessage(int fd); + std::string getClientNickname(int fd); + std::string getClientHostName(int fd); + class IsClientWithFd { + public: + IsClientWithFd(int fd) : fd_(fd) {} + bool operator()(const client& c) const { + return c.get_client_pfd().fd == fd_; + } + private: + int fd_; + }; +}; +#endif \ No newline at end of file diff --git a/server.o b/server.o deleted file mode 100644 index 1cbfda0..0000000 Binary files a/server.o and /dev/null differ diff --git a/topicCmd.cpp b/topicCmd.cpp new file mode 100644 index 0000000..860ed7a --- /dev/null +++ b/topicCmd.cpp @@ -0,0 +1,51 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::topicCmd(std::vector& args, int fd) { + + const std::string& channelName = args[0]; + std::map::iterator it = channels.find(channelName); + + if (it == channels.end()) { + std::string msg = ":" + getClientHostName(fd) + " 403 " + getClientNickname(fd) + " " + channelName + " :No such channel\r\n"; + sendMessage(fd, msg); + } + else if (args.size() == 1) { + const std::string& topic = it->second.getTopic(); + if (topic.empty()) { + std::string msg = ":" + getClientHostName(fd) + " 331 " + getClientNickname(fd) + " " + channelName + " :No topic is set\r\n"; + sendMessage(fd, msg); + } + else { + std::string msg = ":" + getClientHostName(fd) + " 332 " + getClientNickname(fd) + " " + channelName + " :" + topic + "\r\n"; + sendMessage(fd, msg); + } + } + else { + // Set topic + std:: string newTopic = args[1]; + for (size_t i = 2; i < args.size(); ++i) { + newTopic += " " + args[i]; + } + std::string msg = ":" + getClientNickname(fd) + "!" + getClientNickname(fd) + "@" + getClientHostName(fd) + " TOPIC " + channelName + " :" + newTopic + "\r\n"; + sendMessage(fd, msg); + + // notify all clients in the channel + std::map::const_iterator clientIt; + const std::map& clients = it->second.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (clientIt->first != fd) { + sendMessage(clientIt->first, msg); + } + } + + Channel& channel = it->second; + channel.setTopic(newTopic); + } +} + + diff --git a/utils.cpp b/utils.cpp new file mode 100644 index 0000000..62f41d1 --- /dev/null +++ b/utils.cpp @@ -0,0 +1,18 @@ +#include "utils.hpp" + +void sendMessage(int fd, const std::string& message) { + if (send(fd, message.c_str(), message.size(), 0) == -1) { + perror("send"); + } +} + +std::vector split(std::string line, char c) { + std::vector vec; + size_t pos; + while ((pos = line.find(c)) != std::string::npos) { + vec.push_back(line.substr(0, pos)); + line.erase(0, pos + 1); + } + vec.push_back(line); + return vec; +} \ No newline at end of file diff --git a/utils.hpp b/utils.hpp new file mode 100644 index 0000000..d056f4d --- /dev/null +++ b/utils.hpp @@ -0,0 +1,11 @@ +#ifndef UTILS_HPP +#define UTILS_HPP + +#include +#include +#include + +void sendMessage(int fd, const std::string& message); +std::vector split(std::string line, char c); + +#endif // UTILS_HPP \ No newline at end of file diff --git a/whocmd.cpp b/whocmd.cpp new file mode 100644 index 0000000..7546ce4 --- /dev/null +++ b/whocmd.cpp @@ -0,0 +1,58 @@ +#include "server.hpp" +#include "client.hpp" +#include +#include +#include +#include "utils.hpp" + +void Server::whoCmd(std::vector& args, int fd) { + if (args.size() == 0) { + // No channel name provided + std::string msg = "431 " + getClientNickname(fd) + " :No channel given\n"; + sendMessage(fd, msg); + return; + } + + const std::string& channelName = args[0]; + std::map::iterator it = channels.find(channelName); + + if (it == channels.end()) { + // Channel not found + std::string msg = "403 " + getClientNickname(fd) + " " + channelName + " :No such channel\n"; + sendMessage(fd, msg); + } else { + // Channel exists, prepare to list the clients + Channel& channel = it->second; + std::string msg; + + msg = ":" + getClientHostName(fd) + " 353 " + getClientNickname(fd) + " = " + channelName + " :"; + + // List all clients in the channel + bool first = true; + std::map::const_iterator clientIt; + const std::map& clients = channel.getClientsFromChannel(); + for (clientIt = clients.begin(); clientIt != clients.end(); ++clientIt) { + if (!first) { + msg += " "; + } + first = false; + // msg += clientIt->second.getNickname(); // Adjust if you need more details + // check if the client is an operator + if (channel.isOperator(clientIt->first)) { + std::cout << "Operator: " << clientIt->second.getNickname() << std::endl; + msg += "@" + clientIt->second.getNickname(); + } else { + msg += clientIt->second.getNickname(); + std::cout << "Not Operator: " << clientIt->second.getNickname() << std::endl; + } + } + + msg += "\n"; + + // End of list message + msg += ":" + getClientNickname(fd) + " 366 " + getClientNickname(fd) + " " + channelName + " :End of /WHO list.\n"; + + // Send the response to the requesting client + sendMessage(fd, msg); + } +}