/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2021, 2024 Sadie Powell * * 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 . */ #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); } } void TreeSocket::WriteLine(const std::string& original_line) { 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, "FAIL") || irc::equals(command, "WARN") || irc::equals(command, "NOTE")) { // [...] : 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); } // 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) ); } } else if (irc::equals(command, "FJOIN")) { // : FJOIN :[],:/ [],:/ // ^^^^^^^^^ 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) { 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; } } } else if (irc::equals(command, "IJOIN")) { // : IJOIN [ ] // ^^^^^^^^ 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); } } if (line != original_line) { ServerInstance->Logs.Debug(MODNAME, "Before compat: {}", original_line); ServerInstance->Logs.Debug(MODNAME, "After compat: {}", line); } WriteLineInternal(line); } bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, CommandBase::Params& params) { if (irc::equals(cmd, "IJOIN")) { if (params.size() < 3) return false; // Malformed. // : IJOIN [ ] // ^^^^^^^^ New in 1207 params.insert(params.begin() + 2, "0"); } return true; }