The complete source code of IdealIRC http://www.idealirc.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
idealirc/IRCClient/Commands/handleNumeric.cpp

135 lines
5.1 KiB

/*
* IdealIRC Core - Internet Relay Chat API
* Copyright (C) 2021 Tom-Andre Barstad.
* This software is licensed under the Software Attribution License.
* See LICENSE for more information.
*/
#include "../IRCBase.h"
#include "../IRCBasePriv.h"
#include "../Commands.h"
void IRCBasePriv::handleNumeric(const IRCMessage& ircmessage) {
using namespace Numeric;
if (!isOnline && ircmessage == RPL_ISUPPORT) {
// Note: skip the first item (argument), it is always our nickname
for (auto it = ircmessage.getArgs().cbegin() + 1; it != ircmessage.getArgs().cend(); ++it) {
const auto& arg = *it;
std::string key, val;
auto delim = std::find(arg.begin(), arg.end(), '=');
if (delim != arg.end()) {
key = std::string(arg.begin(), delim);
val = std::string(delim + 1, arg.end());
}
else
key = arg;
isupport.insert_or_assign(key, val);
}
const std::string& prefix = isupport.find("PREFIX")->second;
validPrivilegeModes = std::string(std::find(prefix.begin(), prefix.end(), '(') + 1,
std::find(prefix.begin(), prefix.end(), ')'));
validPrivilegeSymbols = std::string(std::find(prefix.begin(), prefix.end(), ')') + 1,
prefix.end());
}
else if (!isOnline && (ircmessage == RPL_ENDOFMOTD || ircmessage == ERR_NOMOTD)) {
nickname = ircmessage[0];
isOnline = true;
if (keepaliveFreq > std::chrono::seconds(0))
startKeepaliveTimer();
// Emplace ourself in the all-members list.
allMembers.emplace_back(std::make_shared<IRCMember>(IRCPrefix::fromNickname(nickname)));
super.onRegistered();
}
else if (ircmessage == RPL_NAMREPLY) {
auto chan = super.getChannel(ircmessage[2]);
if (chan && chan->isPopulating()) {
std::istringstream ss(ircmessage.getMessage());
/*
* Note these things:
* A member may contain a usermode.
* IRCv3 may enable multiple usermodes (multi-prefix).
* IRCv3 may enable each member entry to be a full hostmask (userhost-in-names) and not only a nickname.
*/
auto members = std::vector<std::string>(std::istream_iterator<std::string>{ ss },
std::istream_iterator<std::string>());
for (std::string& namem : members) {
/* Extract mode symbols */
auto memBegin = std::find_if_not(namem.begin(), namem.end(),
[this](char ms) {
return isMemberPrivilegeSymbol(ms);
});
std::string modesymbols = std::string(namem.begin(), memBegin);
namem.erase(namem.begin(), memBegin);
std::optional<IRCPrefix> memprefix;
/* IRC standard reply */
if (namem.find('!') == std::string::npos)
memprefix.emplace(IRCPrefix::fromNickname(namem));
/* IRCv3 reply */
else
memprefix.emplace(namem);
auto mem = super.getMember(memprefix->nickname());
if (!mem) {
mem = std::make_shared<IRCMember>(*memprefix);
allMembers.push_back(mem);
}
if (mem->prefix().host().empty() && !memprefix->host().empty())
mem->setPrefix(*memprefix);
mem->addChannel(chan);
auto& entry = chan->addMember(mem);
for (char s : modesymbols) {
char letter = memberPrivilegeSymbolToMode(s);
if (letter != '\0')
entry.addMode(letter);
}
}
}
}
else if (ircmessage == RPL_ENDOFNAMES) {
auto chan = super.getChannel(ircmessage[1]);
if (chan && chan->isPopulating())
chan->donePopulating();
}
else if (ircmessage == RPL_TOPIC) {
auto chan = super.getChannel(ircmessage[1]);
if (chan)
chan->setTopic(ircmessage.getMessage());
}
else if (ircmessage == RPL_CHANNELMODEIS) {
auto chan = super.getChannel(ircmessage[1]);
const std::string& modes = ircmessage[2];
auto args = ircmessage.getArgs();
args.erase(args.begin(), args.begin() + 3);
if (chan)
parseChannelModeMessage(chan, modes, args);
}
else if (ircmessage == NumericV3::RPL_SASLSUCCESS && saslInProgress) {
saslInProgress = false;
writeNoMsg(Command::IRCv3::CAP, { Command::IRCv3::END });
}
else if (ircmessage == NumericV3::ERR_SASLFAIL && saslInProgress) {
saslInProgress = false;
super.disconnectFromServer();
}
super.onMsgNumeric(ircmessage.getSender(), ircmessage.getCommand(), ircmessage.getArgs(), ircmessage.getMessage());
}