diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/modules/m_spanningtree/commands.h | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree/compat.cpp | 70 | ||||
-rw-r--r-- | src/modules/m_spanningtree/ftopic.cpp | 18 | ||||
-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/netburst.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_spanningtree/protocolinterface.cpp | 4 | ||||
-rw-r--r-- | src/modules/m_spanningtree/treesocket.h | 4 | ||||
-rw-r--r-- | src/modules/m_spanningtree/treesocket2.cpp | 6 |
9 files changed, 130 insertions, 18 deletions
diff --git a/src/modules/m_spanningtree/commands.h b/src/modules/m_spanningtree/commands.h index 7e171aa99..dd54b5b6b 100644 --- a/src/modules/m_spanningtree/commands.h +++ b/src/modules/m_spanningtree/commands.h @@ -107,7 +107,7 @@ class CommandFMode : public Command class CommandFTopic : public Command { public: - CommandFTopic(Module* Creator) : Command(Creator, "FTOPIC", 4) { flags_needed = FLAG_SERVERONLY; } + CommandFTopic(Module* Creator) : Command(Creator, "FTOPIC", 5) { flags_needed = FLAG_SERVERONLY; } CmdResult Handle (const std::vector<std::string>& parameters, User *user); RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) { return ROUTE_BROADCAST; } }; diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp index bfc2d1560..30b7ba8bb 100644 --- a/src/modules/m_spanningtree/compat.cpp +++ b/src/modules/m_spanningtree/compat.cpp @@ -90,6 +90,46 @@ 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); + } + } + else if (command == "FTOPIC") + { + // Drop channel TS for FTOPIC + // :sid FTOPIC #target TS TopicTS ... + // 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; + + std::string::size_type d = line.find(' ', c + 1); + if (d == std::string::npos) + return; + + line.erase(c, d-c); + } } } } @@ -98,3 +138,33 @@ 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); + } + else if ((cmd == "FTOPIC") && (params.size() >= 4)) + { + // :20D FTOPIC #channel 100 Attila :topic text + return InsertCurrentChannelTS(params); + } + + return true; // Passthru +} diff --git a/src/modules/m_spanningtree/ftopic.cpp b/src/modules/m_spanningtree/ftopic.cpp index 918bb7f2c..69d3af565 100644 --- a/src/modules/m_spanningtree/ftopic.cpp +++ b/src/modules/m_spanningtree/ftopic.cpp @@ -28,7 +28,15 @@ CmdResult CommandFTopic::Handle(const std::vector<std::string>& params, User *us if (!c) return CMD_FAILURE; - time_t ts = ConvToInt(params[1]); + time_t ChanTS = ConvToInt(params[1]); + if (!ChanTS) + return CMD_INVALID; + + if (c->age < ChanTS) + // Our channel TS is older, nothing to do + return CMD_FAILURE; + + time_t ts = ConvToInt(params[2]); if (!ts) return CMD_INVALID; @@ -42,18 +50,18 @@ CmdResult CommandFTopic::Handle(const std::vector<std::string>& params, User *us * string comparision, so non-empty topics always overridde * empty topics if their timestamps are equal */ - if ((ts == c->topicset) && (c->topic > params[3])) + if ((ts == c->topicset) && (c->topic > params[4])) return CMD_FAILURE; // Topics were set at the exact same time, keep our topic and setter - if (c->topic != params[3]) + if (c->topic != params[4]) { // Update topic only when it differs from current topic - c->topic.assign(params[3], 0, ServerInstance->Config->Limits.MaxTopic); + c->topic.assign(params[4], 0, ServerInstance->Config->Limits.MaxTopic); c->WriteChannel(user, "TOPIC %s :%s", c->name.c_str(), c->topic.c_str()); } // Update setter and settime - c->setby.assign(params[2], 0, 127); + c->setby.assign(params[3], 0, 127); c->topicset = ts; return CMD_SUCCESS; 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/netburst.cpp b/src/modules/m_spanningtree/netburst.cpp index 566224c7a..a77623bfc 100644 --- a/src/modules/m_spanningtree/netburst.cpp +++ b/src/modules/m_spanningtree/netburst.cpp @@ -161,7 +161,7 @@ void TreeSocket::SyncChannel(Channel* chan) SendFJoins(chan); if (!chan->topic.empty()) { - snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s", ServerInstance->Config->GetSID().c_str(), chan->name.c_str(), (unsigned long)chan->topicset, chan->setby.c_str(), chan->topic.c_str()); + snprintf(data,MAXBUF,":%s FTOPIC %s %lu %lu %s :%s", ServerInstance->Config->GetSID().c_str(), chan->name.c_str(), (unsigned long) chan->age, (unsigned long)chan->topicset, chan->setby.c_str(), chan->topic.c_str()); this->WriteLine(data); } diff --git a/src/modules/m_spanningtree/protocolinterface.cpp b/src/modules/m_spanningtree/protocolinterface.cpp index d79765662..93a138758 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("*"); @@ -78,6 +81,7 @@ void SpanningTreeProtocolInterface::SendTopic(Channel* channel, std::string &top parameterlist params; params.push_back(channel->name); + params.push_back(ConvToStr(channel->age)); params.push_back(ConvToStr(ServerInstance->Time())); params.push_back(ServerInstance->Config->ServerName); params.push_back(":" + topic); 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") { |