This commit is contained in:
root
2026-05-28 12:43:25 +00:00
parent f221c92fec
commit f1a7e3e8f7
4 changed files with 420 additions and 0 deletions
+316
View File
@@ -36,6 +36,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;
}
ConnectedUser::ConnectedUser(void) : fd(-1), passOk(false), nickOk(false), userOk(false)
@@ -109,6 +110,8 @@ void Server::acceptNew(void)
if (newFd == -1)
throw std::runtime_error(strerror(errno));
fcntl(newFd, F_SETFL, O_NONBLOCK);
int flag = 1;
setsockopt(newFd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
struct pollfd pfd;
pfd.fd = newFd;
pfd.events = POLLIN;
@@ -191,6 +194,20 @@ void Server::dispatch(int fd, const IrcMessage &msg)
handlePing(fd, msg);
else if (cmd == "QUIT")
handleQuit(fd, msg);
else if (cmd == "JOIN")
handleJoin(fd, msg);
else if (cmd == "PART")
handlePart(fd, msg);
else if (cmd == "PRIVMSG")
handlePrivmsg(fd, msg);
else if (cmd == "KICK")
handleKick(fd, msg);
else if (cmd == "INVITE")
handleInvite(fd, msg);
else if (cmd == "TOPIC")
handleTopic(fd, msg);
else if (cmd == "MODE")
handleMode(fd, msg);
}
void Server::handlePass(int fd, const IrcMessage &msg)
@@ -243,4 +260,303 @@ void Server::handleQuit(int fd, const IrcMessage &msg)
{
removeUser(fd);
(void)msg;
}
void Server::broadcastToChannel(const std::string &chanName, const std::string &msg, int exceptFd)
{
Channel &chan = _channels[chanName];
const std::vector<int> &members = chan.getMembers();
for (std::vector<int>::const_iterator it = members.begin(); it != members.end(); ++it)
{
if (*it != exceptFd)
sendReply(*it, msg);
}
}
void Server::handleJoin(int fd, const IrcMessage &msg)
{
std::string chanName = msg.param(0);
if (!chanName.empty() && chanName[0] != '#')
{
sendReply(fd, "403 " + chanName + " :No such channel\r\n");
return ;
}
if (_channels.find(chanName) == _channels.end())
_channels.insert(std::make_pair(chanName, Channel(chanName)));
Channel &chan = _channels[chanName];
if (chan.isInviteOnly() && !chan.isInvited(fd))
{
sendReply(fd, "473 " + chanName + " :Cannot join channel (+i)\r\n");
return ;
}
if (chan.getKey() != "" && (msg.paramCount() < 2 || msg.param(1) != chan.getKey()))
{
sendReply(fd, "475 " + chanName + " :Cannot join channel (+k)\r\n");
return ;
}
if (chan.getUserLimit() > 0 && chan.memberCount() >= chan.getUserLimit())
{
sendReply(fd, "471 " + chanName + " :Cannot join channel (+l)\r\n");
return ;
}
if (chan.hasMember(fd))
return ;
chan.addMember(fd);
if (chan.memberCount() == 1)
chan.addOperator(fd);
std::string msg_add = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost JOIN " + chanName + "\r\n";
broadcastToChannel(chanName, msg_add, -1);
if (chan.getTopic() != "")
sendReply(fd, "332 " + _users[fd].nick + " " + chanName + " :" + chan.getTopic() + "\r\n");
}
void Server::handlePart(int fd, const IrcMessage &msg)
{
std::string chanName = msg.param(0);
if (_channels.find(chanName) == _channels.end())
{
sendReply(fd, "403 " + chanName + " :No such channel\r\n");
return ;
}
Channel &chan = _channels[chanName];
if (!chan.hasMember(fd))
{
sendReply(fd, "442 " + chanName + " :You're not on that channel\r\n");
return ;
}
std::string msg_rm = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost PART " + chanName + "\r\n";
broadcastToChannel(chanName, msg_rm, -1);
chan.removeMember(fd);
if (chan.memberCount() == 0)
_channels.erase(chanName);
}
void Server::handlePrivmsg(int fd, const IrcMessage &msg)
{
std::string target = msg.param(0);
std::string text = msg.param(1);
std::string mess = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost PRIVMSG " + target + " :" + text + "\r\n";
if (target[0] == '#')
{
if (_channels.find(target) == _channels.end())
{
sendReply(fd, "403 " + target + " :No such channel\r\n");
return ;
}
Channel &chan = _channels[target];
if (!chan.hasMember(fd))
{
sendReply(fd, "404 " + target + " :Cannot send to channel\r\n");
return ;
}
broadcastToChannel(target, mess, fd);
}
else
{
for (std::map<int, ConnectedUser>::iterator it = _users.begin(); it != _users.end(); ++it)
{
if (it->second.nick == target)
{
sendReply(it->first, mess);
return;
}
}
sendReply(fd, "401 " + target + " :No such nick\r\n");
}
}
void Server::handleKick(int fd, const IrcMessage &msg)
{
std::string chanName = msg.param(0);
std::string targetNick = msg.param(1);
if (_channels.find(chanName) == _channels.end())
{
sendReply(fd, "403 " + chanName + " :No such channel\r\n");
return ;
}
Channel &chan = _channels[chanName];
if (!chan.hasMember(fd))
{
sendReply(fd, "442 " + chanName + " :You're not on that channel\r\n");
return ;
}
if (!chan.isOperator(fd))
{
sendReply(fd, "482 " + chanName + " :You're not channel operator\r\n");
return ;
}
std::map<int, ConnectedUser>::iterator it = _users.begin();
int targetFd = -1;
for (; it != _users.end(); it++)
{
if (it->second.nick == targetNick)
{
targetFd = it->first;
break ;
}
}
if (targetFd == -1)
{
sendReply(fd, "401 " + targetNick + " :No such nick\r\n");
return ;
}
if (!chan.hasMember(targetFd))
{
sendReply(fd, "441 " + targetNick + " " + chanName + " :They aren't on that channel\r\n");
return ;
}
std::string kick_msg = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost KICK " + chanName + " " + targetNick + "\r\n";
broadcastToChannel(chanName, kick_msg, -1);
chan.removeMember(targetFd);
}
void Server::handleInvite(int fd, const IrcMessage &msg)
{
std::string targetNick = msg.param(0);
std::string chanName = msg.param(1);
if (_channels.find(chanName) == _channels.end())
{
sendReply(fd, "403 " + chanName + " :No such channel\r\n");
return ;
}
Channel &chan = _channels[chanName];
if (!chan.hasMember(fd))
{
sendReply(fd, "442 " + chanName + " :You're not on that channel\r\n");
return ;
}
if (!chan.isOperator(fd))
{
sendReply(fd, "482 " + chanName + " :You're not channel operator\r\n");
return ;
}
std::map<int, ConnectedUser>::iterator it = _users.begin();
int targetFd = -1;
for (; it != _users.end(); it++)
{
if (it->second.nick == targetNick)
{
targetFd = it->first;
break ;
}
}
if (targetFd == -1)
{
sendReply(fd, "401 " + targetNick + " :No such nick\r\n");
return ;
}
chan.addInvited(targetFd);
std::string invite_msg = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost INVITE " + targetNick + " " + chanName + "\r\n";
sendReply(targetFd, invite_msg);
}
void Server::handleTopic(int fd, const IrcMessage &msg)
{
std::string chanName = msg.param(0);
if (_channels.find(chanName) == _channels.end())
{
sendReply(fd, "403 " + chanName + " :No such channel\r\n");
return ;
}
Channel &chan = _channels[chanName];
if (!chan.hasMember(fd))
{
sendReply(fd, "442 " + chanName + " :You're not on that channel\r\n");
return ;
}
if (msg.paramCount() == 1)
{
if (chan.getTopic() != "")
sendReply(fd, "332 " + _users[fd].nick + " " + chanName + " :" + chan.getTopic() + "\r\n");
else
sendReply(fd, "331 " + _users[fd].nick + " " + chanName + " :No topic is set\r\n");
return ;
}
if (chan.isTopicRestricted() && !chan.isOperator(fd))
{
sendReply(fd, "482 " + chanName + " :You're not channel operator\r\n");
return ;
}
chan.setTopic(msg.param(1));
std::string bd_msg = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost TOPIC " + chanName + " :" + chan.getTopic() + "\r\n";
broadcastToChannel(chanName, bd_msg, -1);
}
void Server::handleMode(int fd, const IrcMessage &msg)
{
std::string chanName = msg.param(0);
std::string modeStr = msg.param(1);
if (chanName.empty() || chanName[0] != '#')
return ;
if (_channels.find(chanName) == _channels.end())
{
sendReply(fd, "403 " + chanName + " :No such channel\r\n");
return ;
}
Channel &chan = _channels[chanName];
if (!chan.hasMember(fd))
{
sendReply(fd, "442 " + chanName + " :You're not on that channel\r\n");
return ;
}
if (!chan.isOperator(fd))
{
sendReply(fd, "482 " + chanName + " :You're not channel operator\r\n");
return ;
}
bool adding = (modeStr[0] == '+');
char mode = modeStr[1];
if (mode == 'i')
chan.setInviteOnly(adding);
else if (mode == 't')
chan.setTopicRestricted(adding);
else if (mode == 'k')
if (adding)
if (msg.paramCount() >= 3)
chan.setKey(msg.param(2));
else
return ;
else
chan.setKey("");
else if (mode == 'o')
{
if (msg.paramCount() >= 3)
{
std::map<int, ConnectedUser>::iterator it = _users.begin();
int targetFd = -1;
for (; it != _users.end(); it++)
{
if (it->second.nick == msg.param(2))
{
targetFd = it->first;
break ;
}
}
if (targetFd == -1)
{
sendReply(fd, "401 " + msg.param(2) + " :No such nick\r\n");
return ;
}
if (adding)
chan.addOperator(targetFd);
else
chan.removeOperator(targetFd);
}
else
return ;
}
else if (mode == 'l')
{
if (adding)
{
if (msg.paramCount() >= 3)
chan.setUserLimit((size_t)atoi(msg.param(2).c_str()));
else
return ;
}
else
chan.setUserLimit(0);
}
std::string mod_msg = ":" + _users[fd].nick + "!" + _users[fd].username + "@localhost MODE " + chanName + " " + modeStr + "\r\n";
broadcastToChannel(chanName, mod_msg, -1);
}