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.
135 lines
5.1 KiB
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());
|
|
} |