From 50c3145225c49c8a71ee134b26639e4fe09264a2 Mon Sep 17 00:00:00 2001
From: brain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>
Date: Wed, 26 Jul 2006 15:17:43 +0000
Subject: Migrate towards FMODE with TS, remove the SYNCTS command idea

git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@4546 e03df62e-2008-0410-955e-edbf42e46eb7
---
 src/modules/m_spanningtree.cpp | 146 +++++++++++++++++++++++++++++++++--------
 1 file changed, 120 insertions(+), 26 deletions(-)

(limited to 'src')

diff --git a/src/modules/m_spanningtree.cpp b/src/modules/m_spanningtree.cpp
index 5d04c1343..d8ac2d074 100644
--- a/src/modules/m_spanningtree.cpp
+++ b/src/modules/m_spanningtree.cpp
@@ -884,18 +884,79 @@ class TreeSocket : public InspSocket
 	/* FMODE command */
 	bool ForceMode(std::string source, std::deque<std::string> &params)
 	{
-		if (params.size() < 2)
-			return true;
+		if (params.size() < 3)
+		{
+			this->WriteLine("ERROR :Version 1.0 FMODE sent to version 1.1 server");
+			return false;
+		}
 		userrec* who = new userrec();
 		who->fd = FD_MAGIC_NUMBER;
 		const char* modelist[64];
+		time_t TS = 0;
+		int n = 0;
 		memset(&modelist,0,sizeof(modelist));
-		for (unsigned int q = 0; q < params.size(); q++)
+		for (unsigned int q = 0; q < params.size(); q++, n++)
 		{
-			modelist[q] = (char*)params[q].c_str();
+			if (q == 1)
+			{
+				/* The timestamp */
+				TS = atoi(params[q].c_str());
+			}
+			modelist[n] = params[q].c_str();
+		}
+                // Insert the TS value of the object, either userrec or chanrec
+		userrec* a = Srv->FindNick(params[0]);
+		time_t ourTS = 0;
+		if (a)
+		{
+			ourTS = a->age;
+		}
+		//classbase* a = reinterpret_cast<classbase*>(Srv->FindNick(params[0]));
+		else
+		{
+			chanrec* a = Srv->FindChannel(params[0]);
+			if (a)
+			{
+				ourTS = a->age;
+			}
+		}
+		/* U-lined servers always win regardless of their TS */
+		if ((TS > ourTS) && (!Srv->IsUlined(source)))
+		{
+			/* Bounce the mode back to its sender.
+			 * We use our higher TS, so the other end
+			 * SHOULD accept it, if its clock is right.
+			 * If its clock is wrong well bully for you :p
+			 */
+			params[1] = ConvToStr(ourTS);
+			/* Invert the mode string by changing + to -,
+			 * and - to + in the first param.
+			 */
+			for (std::string::iterator x = params[2].begin(); x != params[2].end(); x++)
+			{
+				switch (*x)
+				{
+					case '-':
+						*x = '+';
+					break;
+					case '+':
+						*x = '-';
+					break;
+				}
+			}
+			DoOneToOne(source,"FMODE",params,source);
+			log(DEBUG,"Mode bounced, our TS less than theirs");
+		}
+		else
+		{
+			if ((Srv->IsUlined(source)) && (TS > ourTS))
+			{
+				WriteOpers("\2WARNING!\2 U-Lined server '%s' has bad TS for '%s' (accepted change): \2SYNC YOUR CLOCKS\2 to avoid this notice",source.c_str(),params[0].c_str());
+			}
+			/* Allow the mode */
+			Srv->SendMode(modelist,params.size(),who);
+			DoOneToAllButSender(source,"FMODE",params,source);
 		}
-		Srv->SendMode(modelist,params.size(),who);
-		DoOneToAllButSender(source,"FMODE",params,source);
 		DELETE(who);
 		return true;
 	}
@@ -1029,6 +1090,11 @@ class TreeSocket : public InspSocket
 							/* We also always let u-lined clients win, no matter what the TS value */
 							log(DEBUG,"Our our channel newer than theirs, accepting their modes");
 							Srv->SendMode((const char**)mode_users,modectr,who);
+							if (ourTS != TS)
+							{
+								log(DEFAULT,"Channel TS for %s changed from %lu to %lu",us,ourTS,TS);
+								us->age = TS;
+							}
 						}
 						else
 						{
@@ -1039,6 +1105,10 @@ class TreeSocket : public InspSocket
 							*mode_users[1] = '-';
 							for (unsigned int x = 0; x < modectr; x++)
 							{
+								if (x == 1)
+								{
+									params.push_back(ConvToStr(us->age));
+								}
 								params.push_back(mode_users[x]);
 							}
 							// tell everyone to bounce the modes. bad modes, bad!
@@ -1059,6 +1129,11 @@ class TreeSocket : public InspSocket
 			{
 				log(DEBUG,"Our our channel newer than theirs, accepting their modes");
 				Srv->SendMode((const char**)mode_users,modectr,who);
+				if (ourTS != TS)
+				{
+					log(DEFAULT,"Channel TS for %s changed from %lu to %lu",us,ourTS,TS);
+					us->age = TS;
+				}
 			}
 			else
 			{
@@ -1067,6 +1142,10 @@ class TreeSocket : public InspSocket
 				*mode_users[1] = '-';
 				for (unsigned int x = 0; x < modectr; x++)
 				{
+					if (x == 1)
+					{
+						params.push_back(ConvToStr(us->age));
+					}
 					params.push_back(mode_users[x]);
 				}
 				DoOneToMany(Srv->GetServerName(),"FMODE",params);
@@ -1077,7 +1156,7 @@ class TreeSocket : public InspSocket
 
 	bool SyncChannelTS(std::string source, std::deque<std::string> &params)
 	{
-		if (params.size() == 2)
+		if (params.size() >= 2)
 		{
 			chanrec* c = Srv->FindChannel(params[0]);
 			if (c)
@@ -1168,7 +1247,7 @@ class TreeSocket : public InspSocket
 	{
 		log(DEBUG,"Sending FJOINs to other server for %s",c->name);
 		char list[MAXBUF];
-		std::string individual_halfops = ":"+Srv->GetServerName()+" FMODE "+c->name;
+		std::string individual_halfops = ":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age);
 		
 		size_t dlen, curlen;
 		dlen = curlen = snprintf(list,MAXBUF,":%s FJOIN %s %lu",Srv->GetServerName().c_str(),c->name,(unsigned long)c->age);
@@ -1178,6 +1257,8 @@ class TreeSocket : public InspSocket
 		CUList *ulist = c->GetUsers();
 		std::vector<userrec*> specific_halfop;
 		std::vector<userrec*> specific_voice;
+		std::string modes = "";
+		std::string params = "";
 
 		for (CUList::iterator i = ulist->begin(); i != ulist->end(); i++)
 		{
@@ -1221,11 +1302,15 @@ class TreeSocket : public InspSocket
 				numusers = 0;
 				for (unsigned int y = 0; y < specific_voice.size(); y++)
 				{
-					this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" +v "+specific_voice[y]->nick);
+					modes.append("v");
+					params.append(specific_voice[y]->nick).append(" ");
+					//this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +v "+specific_voice[y]->nick);
 				}
 				for (unsigned int y = 0; y < specific_halfop.size(); y++)
 				{
-					this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" +h "+specific_halfop[y]->nick);
+					modes.append("h");
+					params.append(specific_halfop[y]->nick).append(" ");
+					//this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +h "+specific_halfop[y]->nick);
 				}
 			}
 		}
@@ -1234,14 +1319,27 @@ class TreeSocket : public InspSocket
 			this->WriteLine(list);
 			for (unsigned int y = 0; y < specific_voice.size(); y++)
 			{
-				this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" +v "+specific_voice[y]->nick);
+				modes.append("v");
+				params.append(specific_voice[y]->nick).append(" ");
+				//this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +v "+specific_voice[y]->nick);
 			}
 			for (unsigned int y = 0; y < specific_halfop.size(); y++)
 			{
-				this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" +h "+specific_halfop[y]->nick);
+				modes.append("h");
+				params.append(specific_halfop[y]->nick).append(" ");
+				//this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +h "+specific_halfop[y]->nick);
 			}
 		}
-		this->WriteLine(":"+Srv->GetServerName()+" SYNCTS "+c->name+" "+ConvToStr(c->age));
+		//std::string modes = "";
+		//std::string params = "";
+                for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++)
+                {
+			modes.append("b");
+			params.append(b->data).append(" ");
+                }
+		/* XXX: Send each channel mode and its params -- we'll need a method for this in ModeHandler? */
+                //FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(c->second,(Module*)TreeProtocolModule,(void*)this));
+		this->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" +"+chanmodes(c,true)+modes+" "+params);
 	}
 
 	/* Send G, Q, Z and E lines */
@@ -1305,18 +1403,11 @@ class TreeSocket : public InspSocket
 		for (chan_hash::iterator c = chanlist.begin(); c != chanlist.end(); c++, iterations++)
 		{
 			SendFJoins(Current, c->second);
-			snprintf(data,MAXBUF,":%s FMODE %s +%s",sn,c->second->name,chanmodes(c->second,true));
-			this->WriteLine(data);
 			if (*c->second->topic)
 			{
 				snprintf(data,MAXBUF,":%s FTOPIC %s %lu %s :%s",sn,c->second->name,(unsigned long)c->second->topicset,c->second->setby,c->second->topic);
 				this->WriteLine(data);
 			}
-			for (BanList::iterator b = c->second->bans.begin(); b != c->second->bans.end(); b++)
-			{
-				snprintf(data,MAXBUF,":%s FMODE %s +b %s",sn,c->second->name,b->data);
-				this->WriteLine(data);
-			}
 			FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(c->second,(Module*)TreeProtocolModule,(void*)this));
 			list.clear();
 			c->second->GetExtList(list);
@@ -2360,10 +2451,6 @@ class TreeSocket : public InspSocket
 				{
 					return this->ForceJoin(prefix,params);
 				}
-				else if (command == "SYNCTS")
-				{
-					return this->SyncChannelTS(prefix,params);
-				}
 				else if (command == "SERVER")
 				{
 					return this->RemoteServer(prefix,params);
@@ -3847,12 +3934,12 @@ class ModuleSpanningTree : public Module
 			if (target_type == TYPE_USER)
 			{
 				userrec* u = (userrec*)target;
-				s->WriteLine(":"+Srv->GetServerName()+" FMODE "+u->nick+" "+modeline);
+				s->WriteLine(":"+Srv->GetServerName()+" FMODE "+u->nick+" "+ConvToStr(u->age)+" "+modeline);
 			}
 			else
 			{
 				chanrec* c = (chanrec*)target;
-				s->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+modeline);
+				s->WriteLine(":"+Srv->GetServerName()+" FMODE "+c->name+" "+ConvToStr(c->age)+" "+modeline);
 			}
 		}
 	}
@@ -3894,6 +3981,13 @@ class ModuleSpanningTree : public Module
 			std::deque<std::string>* params = (std::deque<std::string>*)event->GetData();
 			if (params->size() < 2)
 				return;
+			// Insert the TS value of the object, either userrec or chanrec
+			classbase* a = reinterpret_cast<classbase*>(Srv->FindNick((*params)[0]));
+			if (!a)
+			{
+				a = reinterpret_cast<classbase*>(Srv->FindChannel((*params)[0]));
+			}
+			params->insert(params->begin() + 1,ConvToStr(a->age));
 			DoOneToMany(Srv->GetServerName(),"FMODE",*params);
 		}
 	}
-- 
cgit v1.2.3