/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2021, 2024 Sadie Powell <sadie@witchery.services>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "inspircd.h"
#include "main.h"
namespace
{
size_t NextToken(const std::string& line, size_t start)
{
if (start == std::string::npos || start + 1 > line.length())
return std::string::npos;
return line.find(' ', start + 1);
}
}
bool TreeSocket::PreProcessNewProtocolMessage(User*& who, std::string& cmd, CommandBase::Params& params)
{
if (proto_version == PROTO_INSPIRCD_4)
{
if (insp::casemapped_equals(cmd, "ENCAP"))
{
if (params.size() < 2)
return false; // Malformed.
// :<uuid> ENCAP <target> <command> [<params>...];
CommandBase::Params newparams(params.begin() + 2, params.end());
if (!PreProcessNewProtocolMessage(who, params[1], newparams))
return false; // Malformed.
params.erase(params.begin() + 2, params.end());
params.insert(params.end(), newparams.begin(), newparams.end());
}
else if (insp::casemapped_equals(cmd, "FAIL") || insp::casemapped_equals(cmd, "WARN") || insp::casemapped_equals(cmd, "NOTE"))
{
// <source-sid> <target-uuid> <command> <code> [<params>...] :<message>
if (params.size() < 5)
return false; // Malformed.
// InspIRCd v5 introduced networking of standard replies. For v4 and earlier fall back
// to a notice from the server.
cmd = "NOTICE";
const auto* server = Utils->FindServerID(params[0]);
who = server ? server->ServerUser : this->MyRoot->ServerUser;
const auto has_command = params[2] != "*";
CommandBase::Params newparams;
newparams.push_back(params[1]);
newparams.push_back(FMT::format("*** {}{}{}",
has_command ? params[2] : "",
has_command ? ": " : "",
params.back()
));
std::swap(params, newparams);
}
else if (insp::casemapped_equals(cmd, "FJOIN"))
{
// :<sid> FJOIN <chan> <chants> <modes> :[<modes>],<uuid>:<membid>/<joined> [<modes>],<uuid>:<membid>/<joined>
// ^^^^^^^^^ New in 1207
if (params.size() < 4)
return false; // Malformed
size_t pos = 0;
while (pos != std::string::npos)
{
auto next = NextToken(params[3], pos);
auto slash = params[3].find('/', pos);
if (slash != std::string::npos)
params[3].erase(slash, next - slash);
pos = next;
}
}
else if (insp::casemapped_equals(cmd, "IJOIN"))
{
if (params.size() < 3)
return false; // Malformed.
// :<uuid> IJOIN <chan> <membid> <joints> [<chants> <modes>]
// ^^^^^^^^ New in 1207
params.erase(params.begin() + 2);
}
else if (insp::casemapped_equals(cmd, "SETHOST") || insp::casemapped_equals(cmd, "SETIDENT") || insp::casemapped_equals(cmd, "SETNAME"))
{
// CHG* was merged with SET* in v5. Rewrite to the old commands.
cmd.replace(0, 3, "CHG");
}
}
return true;
}
bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, CommandBase::Params& params)
{
if (insp::casemapped_equals(cmd, "CHGHOST") || insp::casemapped_equals(cmd, "CHGIDENT") || insp::casemapped_equals(cmd, "CHGNAME"))
{
if (params.size() < 2)
return false; // Malformed.
// CHG* and SET* were merged in v5.
cmd.replace(0, 3, "SET");
}
else if (insp::casemapped_equals(cmd, "ENCAP"))
{
if (params.size() < 2)
return false; // Malformed.
// :<uuid> ENCAP <target> <command> [<params>...];
CommandBase::Params newparams(params.begin() + 2, params.end());
if (!PreProcessOldProtocolMessage(who, params[1], newparams))
return false; // Malformed.
params.erase(params.begin() + 2, params.end());
params.insert(params.end(), newparams.begin(), newparams.end());
}
else if (insp::casemapped_equals(cmd, "IJOIN"))
{
if (params.size() < 3)
return false; // Malformed.
// :<uuid> IJOIN <chan> <membid> <joints> [<chants> <modes>]
// ^^^^^^^^ New in 1207
params.insert(params.begin() + 2, "0");
}
return true;
}