diff options
Diffstat (limited to 'src/modules')
-rw-r--r-- | src/modules/m_spanningtree/commands.h | 17 | ||||
-rw-r--r-- | src/modules/m_spanningtree/compat.cpp | 52 | ||||
-rw-r--r-- | src/modules/m_spanningtree/ijoin.cpp | 93 | ||||
-rw-r--r-- | src/modules/m_spanningtree/main.cpp | 31 |
4 files changed, 183 insertions, 10 deletions
diff --git a/src/modules/m_spanningtree/commands.h b/src/modules/m_spanningtree/commands.h index c7dc08b59..7e171aa99 100644 --- a/src/modules/m_spanningtree/commands.h +++ b/src/modules/m_spanningtree/commands.h @@ -133,6 +133,21 @@ class CommandFName : public Command RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } }; +class CommandIJoin : public SplitCommand +{ + public: + CommandIJoin(Module* Creator) : SplitCommand(Creator, "IJOIN", 1) { flags_needed = FLAG_SERVERONLY; } + CmdResult HandleRemote(const std::vector<std::string>& parameters, RemoteUser* user); + RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } +}; + +class CommandResync : public SplitCommand +{ + public: + CommandResync(Module* Creator) : SplitCommand(Creator, "RESYNC", 1) { flags_needed = FLAG_SERVERONLY; } + CmdResult HandleServer(const std::vector<std::string>& parameters, FakeUser* user); +}; + class SpanningTreeCommands { public: @@ -145,6 +160,8 @@ class SpanningTreeCommands CommandUID uid; CommandOpertype opertype; CommandFJoin fjoin; + CommandIJoin ijoin; + CommandResync resync; CommandFMode fmode; CommandFTopic ftopic; CommandFHost fhost; diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp index 32bdb3df8..bfc2d1560 100644 --- a/src/modules/m_spanningtree/compat.cpp +++ b/src/modules/m_spanningtree/compat.cpp @@ -39,6 +39,58 @@ void TreeSocket::WriteLine(std::string line) std::string command = line.substr(a + 1, b-a-1); // now try to find a translation entry // TODO a more efficient lookup method will be needed later + if (proto_version < 1205) + { + if (command == "IJOIN") + { + // Convert + // :<uid> IJOIN <chan> [<ts> [<flags>]] + // to + // :<sid> FJOIN <chan> <ts> + [<flags>],<uuid> + std::string::size_type c = line.find(' ', b + 1); + if (c == std::string::npos) + { + // No TS or modes in the command + // :22DAAAAAB IJOIN #chan + const std::string channame = line.substr(b+1, c-b-1); + Channel* chan = ServerInstance->FindChan(channame); + if (!chan) + return; + + line.push_back(' '); + line.append(ConvToStr(chan->age)); + line.append(" + ,"); + } + else + { + std::string::size_type d = line.find(' ', c + 1); + if (d == std::string::npos) + { + // TS present, no modes + // :22DAAAAAC IJOIN #chan 12345 + line.append(" + ,"); + } + else + { + // Both TS and modes are present + // :22DAAAAAC IJOIN #chan 12345 ov + std::string::size_type e = line.find(' ', d + 1); + if (e != std::string::npos) + line.erase(e); + + line.insert(d, " +"); + line.push_back(','); + } + } + + // Move the uuid to the end and replace the I with an F + line.append(line.substr(1, 9)); + line.erase(4, 6); + line[5] = 'F'; + } + else if (command == "RESYNC") + return; + } } } diff --git a/src/modules/m_spanningtree/ijoin.cpp b/src/modules/m_spanningtree/ijoin.cpp new file mode 100644 index 000000000..2f71ffe27 --- /dev/null +++ b/src/modules/m_spanningtree/ijoin.cpp @@ -0,0 +1,93 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2012-2013 Attila Molnar <attilamolnar@hush.com> + * + * 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 "commands.h" +#include "utils.h" +#include "treeserver.h" +#include "treesocket.h" + +CmdResult CommandIJoin::HandleRemote(const std::vector<std::string>& params, RemoteUser* user) +{ + Channel* chan = ServerInstance->FindChan(params[0]); + if (!chan) + { + // Desync detected, recover + // Ignore the join and send RESYNC, this will result in the remote server sending all channel data to us + ServerInstance->Logs->Log("m_spanningtree", LOG_DEBUG, "Received IJOIN for non-existant channel: " + params[0]); + + parameterlist p; + p.push_back(params[0]); + SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils; + Utils->DoOneToOne(ServerInstance->Config->GetSID(), "RESYNC", p, user->server); + + return CMD_FAILURE; + } + + bool apply_modes; + if (params.size() > 1) + { + time_t RemoteTS = ConvToInt(params[1]); + if (!RemoteTS) + { + ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Invalid TS in IJOIN: " + params[1]); + return CMD_INVALID; + } + + if (RemoteTS < chan->age) + { + ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Attempted to lower TS via IJOIN. Channel=" + params[0] + " RemoteTS=" + params[1] + " LocalTS=" + ConvToStr(chan->age)); + return CMD_INVALID; + } + apply_modes = ((params.size() > 2) && (RemoteTS == chan->age)); + } + else + apply_modes = false; + + chan->ForceJoin(user, apply_modes ? ¶ms[2] : NULL); + return CMD_SUCCESS; +} + +CmdResult CommandResync::HandleServer(const std::vector<std::string>& params, FakeUser* user) +{ + ServerInstance->Logs->Log("m_spanningtree", LOG_DEBUG, "Resyncing " + params[0]); + Channel* chan = ServerInstance->FindChan(params[0]); + if (!chan) + { + // This can happen for a number of reasons, safe to ignore + ServerInstance->Logs->Log("m_spanningtree", LOG_DEBUG, "Channel does not exist"); + return CMD_FAILURE; + } + + SpanningTreeUtilities* Utils = ((ModuleSpanningTree*)(Module*)creator)->Utils; + TreeServer* server = Utils->FindServer(user->server); + if (!server) + return CMD_FAILURE; + + TreeSocket* socket = server->GetSocket(); + if (!socket) + { + ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Received RESYNC with a source that is not directly connected: " + user->uuid); + return CMD_INVALID; + } + + // Send all known information about the channel + socket->SyncChannel(chan); + return CMD_SUCCESS; +} diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 77ef6a0fd..7282baac9 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -47,8 +47,8 @@ ModuleSpanningTree::ModuleSpanningTree() SpanningTreeCommands::SpanningTreeCommands(ModuleSpanningTree* module) : rconnect(module, module->Utils), rsquit(module, module->Utils), svsjoin(module), svspart(module), svsnick(module), metadata(module), - uid(module), opertype(module), fjoin(module), fmode(module), ftopic(module), - fhost(module), fident(module), fname(module) + uid(module), opertype(module), fjoin(module), ijoin(module), resync(module), + fmode(module), ftopic(module), fhost(module), fident(module), fname(module) { } @@ -63,6 +63,8 @@ void ModuleSpanningTree::init() ServerInstance->Modules->AddService(commands->uid); ServerInstance->Modules->AddService(commands->opertype); ServerInstance->Modules->AddService(commands->fjoin); + ServerInstance->Modules->AddService(commands->ijoin); + ServerInstance->Modules->AddService(commands->resync); ServerInstance->Modules->AddService(commands->fmode); ServerInstance->Modules->AddService(commands->ftopic); ServerInstance->Modules->AddService(commands->fhost); @@ -551,20 +553,29 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user) Utils->TreeRoot->UserCount++; } -void ModuleSpanningTree::OnUserJoin(Membership* memb, bool sync, bool created, CUList& excepts) +void ModuleSpanningTree::OnUserJoin(Membership* memb, bool sync, bool created_by_local, CUList& excepts) { // Only do this for local users if (IS_LOCAL(memb->user)) { parameterlist params; - // set up their permissions and the channel TS with FJOIN. - // All users are FJOINed now, because a module may specify - // new joining permissions for the user. params.push_back(memb->chan->name); - params.push_back(ConvToStr(memb->chan->age)); - params.push_back(std::string("+") + memb->chan->ChanModes(true)); - params.push_back(memb->modes+","+memb->user->uuid); - Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FJOIN",params); + if (created_by_local) + { + params.push_back(ConvToStr(memb->chan->age)); + params.push_back(std::string("+") + memb->chan->ChanModes(true)); + params.push_back(memb->modes+","+memb->user->uuid); + Utils->DoOneToMany(ServerInstance->Config->GetSID(),"FJOIN",params); + } + else + { + if (!memb->modes.empty()) + { + params.push_back(ConvToStr(memb->chan->age)); + params.push_back(memb->modes); + } + Utils->DoOneToMany(memb->user->uuid, "IJOIN", params); + } } } |