]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_spanningtree/fjoin.cpp
Fix the cloaking module on C++98 compilers.
[user/henk/code/inspircd.git] / src / modules / m_spanningtree / fjoin.cpp
index 0879e730a0551616533178ebfab4ce0ff798fc8b..962539970fcd85fed63e69cbcc523a24e82134cc 100644 (file)
@@ -1,10 +1,12 @@
 /*
  * InspIRCd -- Internet Relay Chat Daemon
  *
+ *   Copyright (C) 2015, 2018-2020 Sadie Powell <sadie@witchery.services>
+ *   Copyright (C) 2012-2016 Attila Molnar <attilamolnar@hush.com>
+ *   Copyright (C) 2012 Robby <robby@chatbelgie.be>
  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
- *   Copyright (C) 2008 Dennis Friis <peavey@inspircd.org>
- *   Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ *   Copyright (C) 2008, 2012 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2008, 2010 Craig Edwards <brain@inspircd.org>
  *
  * 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
@@ -42,7 +44,7 @@ class FwdFJoinBuilder : public CommandFJoin::Builder
 };
 
 /** FJOIN, almost identical to TS6 SJOIN, except for nicklist handling. */
-CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params)
+CmdResult CommandFJoin::Handle(User* srcuser, Params& params)
 {
        /* 1.1+ FJOIN works as follows:
         *
@@ -70,6 +72,9 @@ CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params)
         * losing side, so only its own modes get applied. Life is simple for those
         * who succeed at internets. :-)
         *
+        * Outside of netbursts, the winning side also resyncs the losing side if it
+        * detects that the other side recreated the channel.
+        *
         * Syntax:
         * :<sid> FJOIN <chan> <TS> <modes> :[<member> [<member> ...]]
         * The last parameter is a list consisting of zero or more channel members
@@ -82,7 +87,7 @@ CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params)
         * drop the link to avoid desync.
         *
         * InspIRCd 2.0 and older required a comma before the uuid even if the user
-        * had no prefix modes on the channel, InspIRCd 2.2 and later does not require
+        * had no prefix modes on the channel, InspIRCd 3.0 and later does not require
         * a comma in this case anymore.
         *
         * <membid> is a positive integer representing the id of the membership.
@@ -119,6 +124,7 @@ CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params)
        const std::string& channel = params[0];
        Channel* chan = ServerInstance->FindChan(channel);
        bool apply_other_sides_modes = true;
+       TreeServer* const sourceserver = TreeServer::Get(srcuser);
 
        if (!chan)
        {
@@ -129,11 +135,19 @@ CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params)
                time_t ourTS = chan->age;
                if (TS != ourTS)
                {
-                       ServerInstance->SNO->WriteToSnoMask('d', "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %ld",
+                       ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Merge FJOIN received for %s, ourTS: %lu, TS: %lu, difference: %ld",
                                chan->name.c_str(), (unsigned long)ourTS, (unsigned long)TS, (long)(ourTS - TS));
                        /* If our TS is less than theirs, we dont accept their modes */
                        if (ourTS < TS)
                        {
+                               // If the source server isn't bursting then this FJOIN is the result of them recreating the channel with a higher TS.
+                               // This happens if the last user on the channel hops and before the PART propagates a user on another server joins. Fix it by doing a resync.
+                               // Servers behind us won't react this way because the forwarded FJOIN will have the correct TS.
+                               if (!sourceserver->IsBursting())
+                               {
+                                       ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Server %s recreated channel %s with higher TS, resyncing", sourceserver->GetName().c_str(), chan->name.c_str());
+                                       sourceserver->GetSocket()->SyncChannel(chan);
+                               }
                                apply_other_sides_modes = false;
                        }
                        else if (ourTS > TS)
@@ -162,14 +176,12 @@ CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params)
                modechangelist.clear();
        }
 
-       TreeServer* const sourceserver = TreeServer::Get(srcuser);
-
        // Build a new FJOIN for forwarding. Put the correct TS in it and the current modes of the channel
        // after applying theirs. If they lost, the prefix modes from their message are not forwarded.
        FwdFJoinBuilder fwdfjoin(chan, sourceserver);
 
        // Process every member in the message
-       irc::tokenstream users(params.back());
+       irc::spacesepstream users(params.back());
        std::string item;
        Modes::ChangeList* modechangelistptr = (apply_other_sides_modes ? &modechangelist : NULL);
        while (users.GetToken(item))
@@ -178,7 +190,7 @@ CmdResult CommandFJoin::Handle(User* srcuser, std::vector<std::string>& params)
        }
 
        fwdfjoin.finalize();
-       fwdfjoin.Forward(sourceserver);
+       fwdfjoin.Forward(sourceserver->GetRoute());
 
        // Set prefix modes on their users if we lost the FJOIN or had equal TS
        if (apply_other_sides_modes)
@@ -266,7 +278,11 @@ void CommandFJoin::RemoveStatus(Channel* c)
 void CommandFJoin::LowerTS(Channel* chan, time_t TS, const std::string& newname)
 {
        if (Utils->AnnounceTSChange)
-               chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :TS for %s changed from %lu to %lu", chan->name.c_str(), newname.c_str(), (unsigned long) chan->age, (unsigned long) TS);
+       {
+               // WriteRemoteNotice is not used here because the message only needs to go to the local server.
+               chan->WriteNotice(InspIRCd::Format("Creation time of %s changed from %s to %s", newname.c_str(),
+                       InspIRCd::TimeString(chan->age).c_str(), InspIRCd::TimeString(TS).c_str()));
+       }
 
        // While the name is equal in case-insensitive compare, it might differ in case; use the remote version
        chan->name = newname;
@@ -278,18 +294,13 @@ void CommandFJoin::LowerTS(Channel* chan, time_t TS, const std::string& newname)
        // Unset all extensions
        chan->FreeAllExtItems();
 
-       // Clear the topic, if it isn't empty then send a topic change message to local users
-       if (!chan->topic.empty())
-       {
-               chan->topic.clear();
-               chan->WriteChannelWithServ(ServerInstance->Config->ServerName, "TOPIC %s :", chan->name.c_str());
-       }
+       // Clear the topic
+       chan->SetTopic(ServerInstance->FakeClient, std::string(), 0);
        chan->setby.clear();
-       chan->topicset = 0;
 }
 
 CommandFJoin::Builder::Builder(Channel* chan, TreeServer* source)
-       : CmdBuilder(source->GetID(), "FJOIN")
+       : CmdBuilder(source, "FJOIN")
 {
        push(chan->name).push_int(chan->age).push_raw(" +");
        pos = str().size();