From dd4de38e5f9687836c51604faadb9ebe7f4d2220 Mon Sep 17 00:00:00 2001 From: iherman- <200969603+iherman-p@users.noreply.github.com> Date: Sat, 23 May 2026 18:39:18 +0200 Subject: [PATCH] Added MODE and invite only functionality --- Channel/Channel.cpp | 29 ++++++++++++++++++++--- Channel/Channel.hpp | 16 ++++++++++--- Makefile | 1 + Server/Server.cpp | 7 ++++-- Server/Server.hpp | 5 ++-- User/User.cpp | 2 +- User/User.hpp | 2 +- cmds/join.cpp | 57 ++++++++++++++++++++++++++------------------- cmds/mode.cpp | 41 ++++++++++++++++++++++++++++++++ 9 files changed, 124 insertions(+), 36 deletions(-) create mode 100644 cmds/mode.cpp diff --git a/Channel/Channel.cpp b/Channel/Channel.cpp index dea045f..9c4c850 100644 --- a/Channel/Channel.cpp +++ b/Channel/Channel.cpp @@ -33,6 +33,8 @@ Channel& Channel::operator=(const Channel &other) name_ = other.name_; members_ = other.members_; operators_ = other.operators_; + isInviteOnly_ = other.isInviteOnly_; + invitedMembers_ = other.invitedMembers_; } // std::cout << "Channel copy assignment operator called" << std::endl; return (*this); @@ -41,7 +43,7 @@ Channel& Channel::operator=(const Channel &other) // Constructor with name -Channel::Channel(std::string &name) : name_(name) { /* std::cout << "Channel with name constructor called" << std::endl; */ } +Channel::Channel(std::string &name) : name_(name), isInviteOnly_(false) { /* std::cout << "Channel with name constructor called" << std::endl; */ } // Getters @@ -62,14 +64,35 @@ void Channel::addOperator(int fd) { this->operators_.insert(fd); } void Channel::removeOperator(int fd) { this->operators_.erase(fd); } bool Channel::hasOperator(int fd) const { return (this->operators_.count(fd) > 0); } -void Channel::broadcast(const std::string &msg, std::map &clients, int excludedFd) +void Channel::broadcast(const std::string &msg, const std::map &clients, int excludedFd) { for (std::set::iterator member = members_.begin(); member != members_.end(); member++) { if ((*member) == excludedFd) continue; - std::map::iterator user = clients.find(*member); + std::map::const_iterator user = clients.find(*member); if (user != clients.end()) user->second.send(msg); } } + +void Channel::setMode(std::string& mode, std::string& args) +{ + bool value; + if (mode[0] == '+') + value = true; + else + value = false; + + // very simple to test + if (mode[1] == 'i') + { + isInviteOnly_ = value; + return ; + } + + (void) args; +} + +bool Channel::isInviteOnly() const { return isInviteOnly_; } +bool Channel::isInvited(int fd) const { return invitedMembers_.count(fd) > 0; } diff --git a/Channel/Channel.hpp b/Channel/Channel.hpp index de852e6..6272cda 100644 --- a/Channel/Channel.hpp +++ b/Channel/Channel.hpp @@ -24,9 +24,13 @@ class Channel { private: std::string name_; - std::set members_; + + std::set members_; std::set operators_; + bool isInviteOnly_; + std::set invitedMembers_; + public: Channel(); Channel(std::string &name); @@ -39,7 +43,6 @@ class Channel std::string getName() const; const std::set &getMembers() const; - // Users void addMember(int fd); void removeMember(int fd); @@ -50,8 +53,15 @@ class Channel void removeOperator(int fd); bool hasOperator(int fd) const; - void broadcast(const std::string &msg, std::map &clients, int excludedFd); + void inviteMember(User& client); // not implemented + void broadcast(const std::string &msg, const std::map &clients, int excludedFd); + + // modes + void setMode(std::string& mode, std::string& args); + + bool isInviteOnly() const; + bool isInvited(int fd) const; }; diff --git a/Makefile b/Makefile index 28e2dab..26dcc6c 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ SRC = main.cpp Server/Server.cpp User/User.cpp \ Channel/Channel.cpp \ cmds/pass.cpp cmds/nick.cpp cmds/user.cpp \ cmds/join.cpp cmds/privmsg.cpp cmds/quit.cpp \ + cmds/mode.cpp HEADERS = Server/Server.hpp User/User.hpp diff --git a/Server/Server.cpp b/Server/Server.cpp index 890a5c3..e17a54c 100644 --- a/Server/Server.cpp +++ b/Server/Server.cpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Server.cpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: aortigos ::iterator Server::removeClient(std::vectorfd << " disconnected " << std::endl; + // should also remove client from all channels its in + clients_.erase(client->fd); return (sockets_.erase(client)); } diff --git a/Server/Server.hpp b/Server/Server.hpp index 9cf9cd1..011a772 100644 --- a/Server/Server.hpp +++ b/Server/Server.hpp @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* Server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: aortigos ::iterator it = channels_.find(args); + // creates channel if (it == channels_.end()) { channels_[args] = Channel(args); @@ -51,29 +52,37 @@ void Server::join_cmd(User &client, std::istringstream &ss) else { if (it->second.hasMember(client.getFd())) - client.send(":" SERVER_NAME " 443 " + client.getNick() + " " + args + " :is already on channel\r\n"); - else { - client.joinChannel(it->first); - it->second.addMember(client.getFd()); - std::string joinMsg = ":" + client.getNick() + "!" + client.getUsername() + "@localhost JOIN " + args + "\r\n"; - channels_[args].broadcast(joinMsg, clients_, -1); - - - std::string namesList = ":" SERVER_NAME " 353 " + client.getNick() + " = " + args + " :"; - const std::set &members = channels_[args].getMembers(); - for (std::set::const_iterator m = members.begin(); m != members.end(); m++) - { - std::map::iterator u = clients_.find(*m); - if (u != clients_.end()) - { - if (channels_[args].hasOperator(*m)) - namesList += "@"; - namesList += u->second.getNick() + " "; - } - } - client.send(namesList + "\r\n"); - client.send(":" SERVER_NAME " 366 " + client.getNick() + " " + args + " :End of /NAMES list\r\n"); + client.send(":" SERVER_NAME " 443 " + client.getNick() + " " + args + " :is already on channel\r\n"); + return ; } + + if (it->second.isInviteOnly() && !it->second.isInvited(client.getFd())) + { + client.send(":" SERVER_NAME " 473 " + client.getNick() + " " + args + " :Cannot join channel (+i)\r\n"); + return ; + } + + it->second.addMember(client.getFd()); + + client.joinChannel(it->first); + + std::string joinMsg = ":" + client.getNick() + "!" + client.getUsername() + "@localhost JOIN " + args + "\r\n"; + channels_[args].broadcast(joinMsg, clients_, -1); + + std::string namesList = ":" SERVER_NAME " 353 " + client.getNick() + " = " + args + " :"; + const std::set &members = channels_[args].getMembers(); + for (std::set::const_iterator m = members.begin(); m != members.end(); m++) + { + std::map::iterator u = clients_.find(*m); + if (u != clients_.end()) + { + if (channels_[args].hasOperator(*m)) + namesList += "@"; + namesList += u->second.getNick() + " "; + } + } + client.send(namesList + "\r\n"); + client.send(":" SERVER_NAME " 366 " + client.getNick() + " " + args + " :End of /NAMES list\r\n"); } } diff --git a/cmds/mode.cpp b/cmds/mode.cpp new file mode 100644 index 0000000..0755477 --- /dev/null +++ b/cmds/mode.cpp @@ -0,0 +1,41 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* mode.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: iherman- > target >> mode; + std::getline(ss, args); + + if (!client.isRegistered()) return (client.send(":" SERVER_NAME " 451 * :You have not registered\r\n")); + if (target.empty() || mode.empty()) return (client.send(":" SERVER_NAME " 461 " + client.getNick() + " MODE :Not enough parameters\r\n")); + + std::map::iterator channel = channels_.find(target); + if (channel == channels_.end()) + { + client.send(":" SERVER_NAME " 403 " + client.getNick() + target + ":No such channel"); + return ; + } + + if (!channel->second.hasOperator(client.getFd())) + { + client.send(std::string(":") + SERVER_NAME + " 482 " + client.getNick() + " " + channel->second.getName() + " :You're not channel operator\r\n"); + return ; + } + + channel->second.setMode(mode, args); +}