diff options
-rw-r--r-- | src/modules/m_spanningtree/compat.cpp | 47 | ||||
-rw-r--r-- | src/modules/m_spanningtree/main.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree/metadata.cpp | 40 | ||||
-rw-r--r-- | src/modules/m_spanningtree/protocolinterface.cpp | 3 | ||||
-rw-r--r-- | src/modules/m_spanningtree/treesocket.h | 4 | ||||
-rw-r--r-- | src/modules/m_spanningtree/treesocket2.cpp | 6 |
6 files changed, 91 insertions, 11 deletions
diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp index bfc2d1560..c14115bed 100644 --- a/src/modules/m_spanningtree/compat.cpp +++ b/src/modules/m_spanningtree/compat.cpp @@ -90,6 +90,28 @@ void TreeSocket::WriteLine(std::string line) } else if (command == "RESYNC") return; + else if (command == "METADATA") + { + // Drop TS for channel METADATA + // :sid METADATA #target TS extname ... + // A B C D + if (b == std::string::npos) + return; + + std::string::size_type c = line.find(' ', b + 1); + if (c == std::string::npos) + return; + + if (line[b + 1] == '#') + { + // We're sending channel metadata + std::string::size_type d = line.find(' ', c + 1); + if (d == std::string::npos) + return; + + line.erase(c, d-c); + } + } } } } @@ -98,3 +120,28 @@ void TreeSocket::WriteLine(std::string line) this->WriteData(line); this->WriteData(newline); } + +namespace +{ + bool InsertCurrentChannelTS(std::vector<std::string>& params) + { + Channel* chan = ServerInstance->FindChan(params[0]); + if (!chan) + return false; + + // Insert the current TS of the channel between the first and the second parameters + params.insert(params.begin()+1, ConvToStr(chan->age)); + return true; + } +} + +bool TreeSocket::PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params) +{ + if ((cmd == "METADATA") && (params.size() >= 3)) + { + // :20D METADATA #channel extname :extdata + return InsertCurrentChannelTS(params); + } + + return true; // Passthru +} diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 7282baac9..a5785f20c 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -899,7 +899,7 @@ void ModuleSpanningTree::ProtoSendMetaData(void* opaque, Extensible* target, con if (u) s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+u->uuid+" "+extname+" :"+extdata); else if (c) - s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+c->name+" "+extname+" :"+extdata); + s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA "+c->name+" "+ConvToStr(c->age)+" "+extname+" :"+extdata); else if (!target) s->WriteLine(":"+ServerInstance->Config->GetSID()+" METADATA * "+extname+" :"+extdata); } diff --git a/src/modules/m_spanningtree/metadata.cpp b/src/modules/m_spanningtree/metadata.cpp index 20e56cb4f..9709ca54c 100644 --- a/src/modules/m_spanningtree/metadata.cpp +++ b/src/modules/m_spanningtree/metadata.cpp @@ -23,27 +23,47 @@ CmdResult CommandMetadata::Handle(const std::vector<std::string>& params, User *srcuser) { - std::string value = params.size() < 3 ? "" : params[2]; - ExtensionItem* item = ServerInstance->Extensions.GetItem(params[1]); if (params[0] == "*") { + std::string value = params.size() < 3 ? "" : params[2]; FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(NULL,params[1],value)); + return CMD_SUCCESS; } - else if (*(params[0].c_str()) == '#') + + if (params[0][0] == '#') { + // Channel METADATA has an additional parameter: the channel TS + // :22D METADATA #channel 12345 extname :extdata + if (params.size() < 3) + return CMD_INVALID; + Channel* c = ServerInstance->FindChan(params[0]); - if (c) - { - if (item) - item->unserialize(FORMAT_NETWORK, c, value); - FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(c,params[1],value)); - } + if (!c) + return CMD_FAILURE; + + time_t ChanTS = ConvToInt(params[1]); + if (!ChanTS) + return CMD_INVALID; + + if (c->age < ChanTS) + // Their TS is newer than ours, discard this command and do not propagate + return CMD_FAILURE; + + std::string value = params.size() < 4 ? "" : params[3]; + + ExtensionItem* item = ServerInstance->Extensions.GetItem(params[2]); + if (item) + item->unserialize(FORMAT_NETWORK, c, value); + FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(c,params[2],value)); } - else if (*(params[0].c_str()) != '#') + else { User* u = ServerInstance->FindUUID(params[0]); if ((u) && (!IS_SERVER(u))) { + ExtensionItem* item = ServerInstance->Extensions.GetItem(params[1]); + std::string value = params.size() < 3 ? "" : params[2]; + if (item) item->unserialize(FORMAT_NETWORK, u, value); FOREACH_MOD(I_OnDecodeMetaData,OnDecodeMetaData(u,params[1],value)); diff --git a/src/modules/m_spanningtree/protocolinterface.cpp b/src/modules/m_spanningtree/protocolinterface.cpp index d79765662..d727f588c 100644 --- a/src/modules/m_spanningtree/protocolinterface.cpp +++ b/src/modules/m_spanningtree/protocolinterface.cpp @@ -63,7 +63,10 @@ void SpanningTreeProtocolInterface::SendMetaData(Extensible* target, const std:: if (u) params.push_back(u->uuid); else if (c) + { params.push_back(c->name); + params.push_back(ConvToStr(c->age)); + } else params.push_back("*"); diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index fcfb0be44..ca5cac038 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -314,4 +314,8 @@ class TreeSocket : public BufferedSocket /** Returns true if this server was introduced to the rest of the network */ bool Introduced(); + + /** Fixes messages coming from old servers so the new command handlers understand them + */ + bool PreProcessOldProtocolMessage(User*& who, std::string& cmd, std::vector<std::string>& params); }; diff --git a/src/modules/m_spanningtree/treesocket2.cpp b/src/modules/m_spanningtree/treesocket2.cpp index cd9afac41..e91214041 100644 --- a/src/modules/m_spanningtree/treesocket2.cpp +++ b/src/modules/m_spanningtree/treesocket2.cpp @@ -298,6 +298,12 @@ void TreeSocket::ProcessConnectedLine(std::string& prefix, std::string& command, if (command == "SVSMODE") // This isn't in an "else if" so we still force FMODE for changes on channels. command = "MODE"; + if (proto_version < ProtocolVersion) + { + if (!PreProcessOldProtocolMessage(who, command, params)) + return; + } + // TODO move all this into Commands if (command == "MAP") { |