From 6732e59a0370709ffe3f4d79fa4412cd9eda8f12 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 4 Jun 2026 21:24:43 +0000 Subject: [PATCH] push --- DEFENSE.txt | 25 ++++++++++++ includes/Server.hpp | 1 + main.cpp | 10 +++++ srcs/IrcMessage.cpp | 5 ++- srcs/Server.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 DEFENSE.txt diff --git a/DEFENSE.txt b/DEFENSE.txt new file mode 100644 index 0000000..eb6c89d --- /dev/null +++ b/DEFENSE.txt @@ -0,0 +1,25 @@ +irssi +/connect localhost 6667 pass +/nick bob +/quote NICK 1abc +/quote PING coucou +/join #test +/quote PRIVMSG #test :salut +/quote PRIVMSG bob :coucou +/part #test +/join #test +/quote TOPIC #test +/quote TOPIC #test :nouveau sujet +/quote MODE #test +i +/quote MODE #test -i +/quote MODE #test +t +/quote MODE #test -t +/quote MODE #test +k secret +/quote MODE #test -k +/quote MODE #test +l 2 +/quote MODE #test -l +/quote MODE #test +o alice +/quote MODE #test -o alice +/quote INVITE alice #test +/quote KICK #test alice +/quote QUIT diff --git a/includes/Server.hpp b/includes/Server.hpp index 8da1954..a205a33 100644 --- a/includes/Server.hpp +++ b/includes/Server.hpp @@ -15,6 +15,7 @@ # include # include # include +# include # include # include "CommandValidator.hpp" # include "Channel.hpp" diff --git a/main.cpp b/main.cpp index 2dfaacc..52cc19a 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,15 @@ #include #include +#include #include "Server.hpp" +volatile sig_atomic_t g_stop = 0; + +void handleSig(int) +{ + g_stop = 1; +} + int main(int argc, char **argv) { if (argc != 3) @@ -15,6 +23,8 @@ int main(int argc, char **argv) std::cerr << "Error: invalid port" << std::endl; return (1); } + signal(SIGINT, handleSig); + signal(SIGQUIT, handleSig); try { Server server(port, argv[2]); diff --git a/srcs/IrcMessage.cpp b/srcs/IrcMessage.cpp index bffe60d..62be1f3 100644 --- a/srcs/IrcMessage.cpp +++ b/srcs/IrcMessage.cpp @@ -53,7 +53,10 @@ bool IrcMessage::hasParam(size_t index) const const std::string &IrcMessage::param(size_t index) const { - return (_params[index]); + static const std::string empty; + if (index >= _params.size()) + return (empty); + return (_params[index]); } size_t IrcMessage::paramCount(void) const diff --git a/srcs/Server.cpp b/srcs/Server.cpp index 4db80fc..2d08307 100644 --- a/srcs/Server.cpp +++ b/srcs/Server.cpp @@ -1,5 +1,7 @@ #include "Server.hpp" +extern volatile sig_atomic_t g_stop; + void Server::start(void) { _serverFd = socket(AF_INET, SOCK_STREAM, 0); @@ -36,7 +38,7 @@ void Server::start(void) pollfd.events = POLLIN; pollfd.revents = 0; _fds.push_back(pollfd); - std::cout << "FT_IRC server startded on " << _port << " Port." << std::endl << "The password is \"" << _password << "\"." << std::endl; + std::cout << "FT_IRC server startded on " << _port << " Port." << std::endl << "The password is \"" << _password << "\"." << std::endl << "Ctrl+c for shutdown the server" << std::endl; } ConnectedUser::ConnectedUser(void) : fd(-1), passOk(false), nickOk(false), userOk(false) @@ -87,11 +89,29 @@ Server::~Server(void) void Server::sendReply(int fd, const std::string &msg) { - send(fd, msg.c_str(), msg.size(), 0); + size_t total = 0; + while (total < msg.size()) + { + ssize_t s = send(fd, msg.c_str() + total, msg.size() - total, 0); + if (s <= 0) + return ; + total += static_cast(s); + } } void Server::removeUser(int fd) { + std::map::iterator it = _channels.begin(); + while (it != _channels.end()) + { + it->second.removeMember(fd); + it->second.removeOperator(fd); + it->second.removeInvited(fd); + if (it->second.memberCount() == 0) + _channels.erase(it++); + else + ++it; + } close(fd); _users.erase(fd); for (size_t i = 0; i < _fds.size(); i++) @@ -108,7 +128,7 @@ void Server::acceptNew(void) { int newFd = accept(_serverFd, NULL, NULL); if (newFd == -1) - throw std::runtime_error(strerror(errno)); + return ; fcntl(newFd, F_SETFL, O_NONBLOCK); int flag = 1; setsockopt(newFd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); @@ -143,12 +163,16 @@ void Server::handleRecv(int fd) _users[fd].parseBuffer.append(buf, n); std::vector messages = _users[fd].parseBuffer.extractMessages(); for (size_t i = 0; i < messages.size(); i++) + { + if (_users.find(fd) == _users.end()) + break ; dispatch(fd, messages[i]); + } } void Server::run(void) { - while (true) + while (!g_stop) { int ret = poll(_fds.data(), _fds.size(), -1); if (ret == -1) @@ -163,8 +187,14 @@ void Server::run(void) removeUser(fd); i--; } - else if ( _fds[i].revents & POLLIN) + else if (_fds[i].revents & POLLIN) + { + size_t before = _fds.size(); handleRecv(_fds[i].fd); + if (_fds.size() < before) + i--; + } + } } } @@ -221,9 +251,38 @@ void Server::handlePass(int fd, const IrcMessage &msg) } } +static bool isNickChar(char c, bool first) +{ + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + return (true); + if (c == '[' || c == ']' || c == '\\' || c == '`' + || c == '_' || c == '^' || c == '{' || c == '|' || c == '}') + return (true); + if (!first && ((c >= '0' && c <= '9') || c == '-')) + return (true); + return (false); +} + +static bool isValidNick(const std::string &nick) +{ + if (nick.empty()) + return (false); + for (size_t i = 0; i < nick.size(); ++i) + { + if (!isNickChar(nick[i], i == 0)) + return (false); + } + return (true); +} + void Server::handleNick(int fd, const IrcMessage &msg) { std::string newNick = msg.param(0); + if (!isValidNick(newNick)) + { + sendReply(fd, "432 * " + newNick + " :Erroneous nickname\r\n"); + return ; + } std::map::iterator it = _users.begin(); for (; it != _users.end(); it++) { @@ -233,8 +292,28 @@ void Server::handleNick(int fd, const IrcMessage &msg) return ; } } + bool wasRegistered = _users[fd].isRegistered(); + std::string oldNick = _users[fd].nick; _users[fd].nick = newNick; _users[fd].nickOk = true; + if (wasRegistered && oldNick != newNick) + { + std::string notice = ":" + oldNick + "!" + _users[fd].username + + "@localhost NICK " + newNick + "\r\n"; + std::map seen; + seen[fd] = true; + for (std::map::iterator cit = _channels.begin(); + cit != _channels.end(); ++cit) + { + if (!cit->second.hasMember(fd)) + continue ; + const std::vector &mem = cit->second.getMembers(); + for (size_t i = 0; i < mem.size(); ++i) + seen[mem[i]] = true; + } + for (std::map::iterator sit = seen.begin(); sit != seen.end(); ++sit) + sendReply(sit->first, notice); + } } void Server::handleUser(int fd, const IrcMessage &msg) @@ -327,6 +406,8 @@ void Server::handlePart(int fd, const IrcMessage &msg) std::string msg_rm = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost PART " + chanName + "\r\n"; broadcastToChannel(chanName, msg_rm, -1); chan.removeMember(fd); + chan.removeOperator(fd); + chan.removeInvited(fd); if (chan.memberCount() == 0) _channels.erase(chanName); } @@ -408,6 +489,8 @@ void Server::handleKick(int fd, const IrcMessage &msg) std::string kick_msg = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost KICK " + chanName + " " + targetNick + "\r\n"; broadcastToChannel(chanName, kick_msg, -1); chan.removeMember(targetFd); + chan.removeOperator(targetFd); + chan.removeInvited(targetFd); } void Server::handleInvite(int fd, const IrcMessage &msg) @@ -486,6 +569,8 @@ void Server::handleMode(int fd, const IrcMessage &msg) { std::string chanName = msg.param(0); std::string modeStr = msg.param(1); + if (modeStr.size() < 2 || (modeStr[0] != '+' && modeStr[0] != '-')) + return ; if (chanName.empty() || chanName[0] != '#') return ; if (_channels.find(chanName) == _channels.end())