aboutsummaryrefslogtreecommitdiffstats
path: root/modules/spanningtree/compat.cpp
diff options
context:
space:
mode:
authorGravatar Sadie Powell2026-03-11 21:54:40 +0000
committerGravatar Sadie Powell2026-03-12 00:18:06 +0000
commitfcb3090055429a108b9837dbd4ba505d9c291129 (patch)
tree5c55fd77d3b24adeda54e250d91b2a44badc9c5d /modules/spanningtree/compat.cpp
parentMark all acting extbans as MATCH_REQUIRE_CHANNEL. (diff)
Rework sending server protocol messages.
- Replace CmdBuilder with MessageBuilder. This has a less footgun API. All message building has to go through this now so we can implement other message formats in the future. - Replace the message parsing in WriteLine with an analogue to PreProcessOldProtocolMessage. This should be much faster. - Move parameter translation from the core to spanningtree. - Change EncodeParameter to return the value instead of updating in place. - Replace the OnBuild*Message events with one OnServerMessage that can now access all parts of the message and change them.
Diffstat (limited to 'modules/spanningtree/compat.cpp')
-rw-r--r--modules/spanningtree/compat.cpp152
1 files changed, 55 insertions, 97 deletions
diff --git a/modules/spanningtree/compat.cpp b/modules/spanningtree/compat.cpp
index e975262d3..a47415185 100644
--- a/modules/spanningtree/compat.cpp
+++ b/modules/spanningtree/compat.cpp
@@ -31,122 +31,80 @@ namespace
}
}
-void TreeSocket::WriteLine(const std::string& original_line)
+bool TreeSocket::PreProcessNewProtocolMessage(User*& who, std::string& cmd, CommandBase::Params& params)
{
- if (LinkState != CONNECTED || proto_version == PROTO_NEWEST)
- {
- // Don't translate connections which have negotiated PROTO_NEWEST or
- // where the protocol hasn't been negotiated yet.
- WriteLineInternal(original_line);
- return;
- }
-
- std::string line = original_line;
- size_t cmdstart = 0;
-
- if (line[0] == '@') // Skip the tags.
- {
- cmdstart = NextToken(line, 0);
- if (cmdstart != std::string::npos)
- cmdstart++;
- }
-
- if (line[cmdstart] == ':') // Skip the prefix.
- {
- cmdstart = NextToken(line, cmdstart);
- if (cmdstart != std::string::npos)
- cmdstart++;
- }
-
- // Find the end of the command.
- size_t cmdend = NextToken(line, cmdstart);
- if (cmdend == std::string::npos)
- cmdend = line.size() - 1;
-
- std::string command(line, cmdstart, cmdend - cmdstart);
if (proto_version == PROTO_INSPIRCD_4)
{
- if (irc::equals(command, "ENCAP"))
+ if (irc::equals(cmd, "ENCAP"))
{
+ if (params.size() < 2)
+ return false; // Malformed.
+
// :<uuid> ENCAP <target> <command> [<params>...];
- const auto targetend = NextToken(line, cmdend);
- const auto commandend = NextToken(line, targetend);
- if (targetend != std::string::npos)
- {
- const auto ecommand = line.substr(targetend + 1, commandend - targetend - 1);
- if (irc::equals(ecommand, "SETHOST") || irc::equals(ecommand, "SETIDENT") || irc::equals(ecommand, "SETNAME"))
- {
- // CHG* was merged with SET* in v5.
- line.replace(targetend + 1, 3, "CHG");
- }
- }
+ 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());
}
- if (irc::equals(command, "FAIL") || irc::equals(command, "WARN") || irc::equals(command, "NOTE"))
+ else if (irc::equals(cmd, "FAIL") || irc::equals(cmd, "WARN") || irc::equals(cmd, "NOTE"))
{
// <source-sid> <target-uuid> <command> <code> [<params>...] :<message>
- const auto sourceend = NextToken(line, cmdend);
- const auto targetend = NextToken(line, sourceend);
- const auto commandend = NextToken(line, targetend);
- const auto codeend = NextToken(line, commandend);
- if (codeend != std::string::npos)
- {
- auto prevpos = codeend;
- for (size_t pos = prevpos; pos != std::string::npos && line[prevpos + 1] != ':'; )
- {
- prevpos = pos;
- pos = NextToken(line, prevpos);
- }
+ if (params.size() < 5)
+ return false; // Malformed.
- // Fall back to a notice.
- const auto has_command = line[targetend + 1] != '*';
- line = FMT::format(":{} NOTICE {} :*** {}{}{}",
- line.substr(cmdend + 1, sourceend - cmdend - 1),
- line.substr(sourceend + 1, targetend - sourceend - 1),
- has_command ? line.substr(targetend + 1, commandend - targetend - 1) : "",
- has_command ? ": " : "",
- line.substr(prevpos + 2)
- );
- }
+ // 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 (irc::equals(command, "FJOIN"))
+ else if (irc::equals(cmd, "FJOIN"))
{
// :<sid> FJOIN <chan> <chants> <modes> :[<modes>],<uuid>:<membid>/<joined> [<modes>],<uuid>:<membid>/<joined>
// ^^^^^^^^^ New in 1207
- const auto chanend = NextToken(line, cmdend);
- const auto chantsend = NextToken(line, chanend);
- const auto modesend = NextToken(line, chantsend);
- if (modesend != std::string::npos)
+ if (params.size() < 4)
+ return false; // Malformed
+
+ size_t pos = 0;
+ while (pos != std::string::npos)
{
- auto pos = modesend;
- while (pos != std::string::npos)
- {
- auto next = NextToken(line, pos);
- auto slash = line.find('/', pos);
- if (slash != std::string::npos)
- line.erase(slash, next - slash);
- pos = next;
- }
+ 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 (irc::equals(command, "IJOIN"))
+ else if (irc::equals(cmd, "IJOIN"))
{
+ if (params.size() < 3)
+ return false; // Malformed.
+
// :<uuid> IJOIN <chan> <membid> <joints> [<chants> <modes>]
- // ^^^^^^^^ New in 1207
- const auto chanend = NextToken(line, cmdend);
- const auto membidend = NextToken(line, chanend);
- const auto jointsend = NextToken(line, membidend);
- if (jointsend != std::string::npos)
- line.erase(membidend, jointsend - membidend);
+ // ^^^^^^^^ New in 1207
+ params.erase(params.begin() + 2);
+ }
+ else if (irc::equals(cmd, "SETHOST") || irc::equals(cmd, "SETIDENT") || irc::equals(cmd, "SETNAME"))
+ {
+ // CHG* was merged with SET* in v5. Rewrite to the old commands.
+ cmd.replace(0, 3, "CHG");
}
}
-
- if (line != original_line)
- {
- ServerInstance->Logs.Debug(MODNAME, "Before compat: {}", original_line);
- ServerInstance->Logs.Debug(MODNAME, "After compat: {}", line);
- }
-
- WriteLineInternal(line);
+ return true;
}
bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, CommandBase::Params& params)
@@ -172,7 +130,7 @@ bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, Comm
params.erase(params.begin() + 2, params.end());
params.insert(params.end(), newparams.begin(), newparams.end());
}
- if (irc::equals(cmd, "IJOIN"))
+ else if (irc::equals(cmd, "IJOIN"))
{
if (params.size() < 3)
return false; // Malformed.