From 88fa6a0c72d8929c9201c1b1898d905debd272ff Mon Sep 17 00:00:00 2001
From: cyan <>
Date: Sun, 21 Sep 2003 11:06:19 +0000
Subject: [PATCH] * Added logging to Synchronet console every time an oper gets
 a server notice   (i.e. assume the console is an oper and privy to all oper
 notices) as per   DigitalMan's relentless nagging ;)  Removed redundant log()
 calls because of   this. * Don't allow servers to connect which have the
 password set as '*' in the   N:Line.  This is useful for leaf servers to
 connect out to their QWK hubs. * reintroduce_nick() is a function which
 re-introduces a nick to the network   from the 'hub' side after the leaf has
 done something bad (i.e. colliding   forwards, or forwards global kill)  It
 ensures that the nick is re-joined to   any channels and is given correct
 modes (both channel and user.) * Thus, reintroduce a nick after a global
 kill, don't squit the offending   server. * Reduce the scope of a SQUIT from
 a leaf server to only allow disconnections   to servers connected to it
 locally. * Don't allow leaf servers to use the intraserver CONNECT command. *
 Only allow U:Lined servers to use the intraserver AKILL command. * Pass along
 user AWAY messages on initial server-to-server synchronization. * SJOIN: (All
 of these fixes *should* fix the nasty "MODE -oooooo" bug and           other
 synchronization issues once and for all.  Keep your fingers          
 crossed.)    - Don't bounce modes if an incoming SJOIN originated from a
 non-local      server.    - Parse SJOIN members appropriately so that they're
 opped/deopped according      to the TS.  Pass on the new members list.    -
 Synchronize the channel TS.  Force the created TS to an integer. * Surprise,
 more 'var' cleanup.

---
 exec/ircd.js | 119 ++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 90 insertions(+), 29 deletions(-)

diff --git a/exec/ircd.js b/exec/ircd.js
index d6ea92492f..8e4f067d14 100644
--- a/exec/ircd.js
+++ b/exec/ircd.js
@@ -401,6 +401,7 @@ function parse_oline_flags(flags) {
 }
 
 function oper_notice(ntype,nmessage) {
+	log(ntype + ": " + nmessage);
 	for(thisoper in Clients) {
 		var oper=Clients[thisoper];
 		if ((oper.mode&USERMODE_OPER) && !oper.parent)
@@ -520,7 +521,9 @@ function remove_kline(kl_hm) {
 }
 
 function connect_to_server(this_cline,the_port) {
-	log("Connecting to server: " + this_cline.host);
+	var connect_sock;
+	var new_id;
+
 	if (!the_port && this_cline.port)
 		the_port = this_cline.port;
 	else if (!the_port)
@@ -540,6 +543,8 @@ function connect_to_server(this_cline,the_port) {
 }
 
 function wallopers(str) {
+	var oper;
+
 	for(thisoper in Clients) {
 		oper=Clients[thisoper];
 		if ((oper.mode&USERMODE_OPER) && !oper.parent)
@@ -1073,6 +1078,7 @@ function IRCClient(socket,new_id,local_client,do_newconn) {
 	this.server_chan_info=IRCClient_server_chan_info;
 	this.server_info=IRCClient_server_info;
 	this.synchronize=IRCClient_synchronize;
+	this.reintroduce_nick=IRCClient_reintroduce_nick;
 	this.ip="";
 	this.linkparent="";
 	if (this.socket && local_client && do_newconn) {
@@ -1181,6 +1187,8 @@ function IRCClient_synchronize() {
 		if ((Clients[my_client].conntype == TYPE_USER) ||
 		    (Clients[my_client].conntype == TYPE_USER_REMOTE)) {
 			this.server_nick_info(Clients[my_client]);
+			if (Clients[my_client].away) 
+				this.rawout(":" + Clients[my_client].nick + " AWAY :" + Clients[my_client].away);
 		}
 	}
 	for (my_channel in Channels) {
@@ -1208,6 +1216,33 @@ function IRCClient_server_nick_info(sni_client) {
 	this.rawout("NICK " + sni_client.nick + " " + sni_client.hops + " " + sni_client.created + " " + sni_client.get_usermode() + " " + sni_client.uprefix + " " + sni_client.hostname + " " + sni_client.servername + " 0 " + ip_to_int(sni_client.ip) + " :" + sni_client.realname);
 }
 
+function IRCClient_reintroduce_nick(nick) {
+	var chan;
+	var cmodes;
+
+	if (!this.server || !nick)
+		return 0;
+
+	this.server_nick_info(nick);
+
+	if (nick.away)
+		this.rawout(":" + nick.nick + " AWAY :" + nick.away);
+
+	for (uchan in nick.channels) {
+		cmodes = "";
+		if (nick.channels[uchan]) {
+			chan = Channels[nick.channels[uchan]];
+			if (chan.ismode(nick.id,CHANLIST_OP))
+				cmodes += "@";
+			if (chan.ismode(nick.id,CHANLIST_VOICE))
+				cmodes += "+";
+			this.rawout("SJOIN " + chan.created + " " + chan.nam + " " + chan.chanmode(true) + " :" + cmodes + nick.nick);
+			if (chan.topic)
+				this.rawout("TOPIC " + chan.nam + " " + chan.topicchangedby + " " + chan.topictime + " :" + chan.topic);
+		}
+	}
+}
+
 function IRCClient_server_chan_info(sni_chan) {
 	this.rawout("SJOIN " + sni_chan.created + " " + sni_chan.nam + " " + sni_chan.chanmode(true) + " :" + sni_chan.occupants())
 	var modecounter=0;
@@ -1620,17 +1655,20 @@ function IRCClient_do_whois(wi) {
 }
 
 function IRCClient_services_msg(svcnick,send_str) {
+	var service_nickname;
+	var service_server;
+
 	if (!send_str) {
 		this.numeric412();
 		return 0;
 	}
 	// First, make sure the nick exists.
-	var service_nickname = searchbynick(svcnick);
+	service_nickname = searchbynick(svcnick);
 	if (!service_nickname) {
 		this.numeric440(svcnick);
 		return 0;
 	}
-	var service_server = searchbyserver(service_nickname.servername);
+	service_server = searchbyserver(service_nickname.servername);
 	if (!service_server || !service_server.isulined) {
 		this.numeric440(svcnick);
 		return 0;
@@ -1939,7 +1977,7 @@ function IRCClient_do_summon(summon_user) {
 
 function IRCClient_do_links(mask) {
 	if (!mask)
-		var mask = "*";
+		mask = "*";
 	for(thisServer in Clients) {
 		var Server=Clients[thisServer];
 		if (Server && (Server.conntype == TYPE_SERVER) &&
@@ -2062,14 +2100,17 @@ function IRCClient_do_join(chan_name,join_key) {
 }
 
 function IRCClient_do_part(chan_name) {
+	var chan;
+	var str;
+
 	if((chan_name[0] != "#") && (chan_name[0] != "&") && !this.parent) {
 		this.numeric403(chan_name);
 		return 0;
 	}
-	var chan = chan_name.toUpperCase();
+	chan = chan_name.toUpperCase();
 	if (Channels[chan] != undefined) {
 		if (this.onchannel(chan)) {
-			var str = "PART " + Channels[chan].nam;
+			str = "PART " + Channels[chan].nam;
 			if (this.parent)
 				this.bcast_to_channel(Channels[chan].nam, str, false);
 			else
@@ -2086,6 +2127,8 @@ function IRCClient_do_part(chan_name) {
 }
 
 function IRCClient_part_all() {
+	var partingChannel;
+
 	for(thisChannel in this.channels) {
 		partingChannel=this.channels[thisChannel];
 		this.do_part(Channels[partingChannel].nam);
@@ -2094,10 +2137,12 @@ function IRCClient_part_all() {
 
 function IRCClient_get_usermode() {
 	var tmp_mode = "+";
+
 	if (this.mode&USERMODE_INVISIBLE)
 		tmp_mode += "i";
 	if (this.mode&USERMODE_OPER)
 		tmp_mode += "o";
+
 	return tmp_mode;
 }
 
@@ -2535,7 +2580,8 @@ function IRCClient_unregistered_commands(command, cmdline) {
 					}
 				}
 			}
-			if (!this_nline) {
+			if (!this_nline || ((this_nline.password == "*") &&
+			    !this.sentps)) {
 				this.quit("ERROR: Server not configured.");
 				return 0;
 			}
@@ -2716,11 +2762,9 @@ function IRCClient_registered_commands(command, cmdline) {
 					if (debug) {
 						debug=false;
 						oper_notice("Notice","Debug mode disabled by " + this.ircnuh);
-						log("!NOTICE debug mode disabled by " + this.ircnuh);
 					} else {
 						debug=true;
 						oper_notice("Notice","Debug mode enabled by " + this.ircnuh);
-						log("!NOTICE debug mode enabled by " + this.ircnuh);
 					}
 					break;
 				case "Y":
@@ -3158,7 +3202,6 @@ function IRCClient_registered_commands(command, cmdline) {
 			} else {
 				this.numeric("491", ":No O:Lines for your host.  Attempt logged.");
 				oper_notice("Notice","Failed OPER attempt by " + this.nick + " (" + this.uprefix + "@" + this.hostname + ")");
-				log("!WARNING " + this.ircnuh + " tried to OPER unsuccessfully!");
 			}
 			break;
 		case "PART":
@@ -3252,7 +3295,6 @@ function IRCClient_registered_commands(command, cmdline) {
 			}
 			this.numeric(382, this.nick + " ircd.conf :Rehashing.");
 			oper_notice("Notice",this.nick + " is rehashing Server config file while whistling innocently");
-			log("!NOTICE Rehashing server config as per " + this.ircnuh);
 			read_config_file();
 			break;
 		case "RESTART":
@@ -3270,7 +3312,6 @@ function IRCClient_registered_commands(command, cmdline) {
 			}
 			var rs_str = "Aieeeee!!!  Restarting server...";
 			oper_notice("Notice",rs_str);
-			log("!WARNING " + rs_str + " per " + this.ircnuh);
 			terminate_everything(rs_str);
 			break;
 		case "SQUIT":
@@ -3668,7 +3709,7 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				ThisOrigin.away = ircstring(cmdline);
 			break;
 		case "CONNECT":
-			if (!cmd[3])
+			if (!cmd[3] || !this.hub)
 				break;
 			if (match_irc_mask(servername, cmd[3])) {
 				ThisOrigin.do_connect(cmd[1],cmd[2]);
@@ -3783,7 +3824,7 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				Channels[cn_tuc]=new Channel(cn_tuc);
 				var chan = Channels[cn_tuc];
 				chan.nam = cmd[2];
-				chan.created = cmd[1];
+				chan.created = parseInt(cmd[1]);
 				chan.topic = "";
 				chan.users = new Array();
 				chan.modelist[CHANLIST_BAN] = new Array();
@@ -3792,12 +3833,12 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				chan.mode = CHANMODE_NONE;
 			}
 			if (cmd[3]) {
-				if (chan.created == cmd[1])
+				if (!ThisOrigin.local || (chan.created == parseInt(cmd[1])))
 					var bounce_modes = false;
 				else
 					var bounce_modes = true;
 
-				if (chan.created >= cmd[1]) {
+				if (chan.created >= parseInt(cmd[1])) {
 					if (mode_args)
 						this.set_chanmode(chan, cmd[3] + " " + mode_args, bounce_modes);
 					else
@@ -3807,7 +3848,10 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				var num_sync_modes = 0;
 				var push_sync_modes = "+";
 				var push_sync_args = "";
+				var new_chan_members = "";
 				for (member in chan_members) {
+					if (new_chan_members)
+						new_chan_members += " ";
 					var is_op = false;
 					var is_voice = false;
 					if (chan_members[member][0] == "@") {
@@ -3824,12 +3868,13 @@ function IRCClient_server_commands(origin, command, cmdline) {
 					member_obj.channels.push(chan.nam.toUpperCase());
 					chan.users.push(member_obj.id);
 					member_obj.bcast_to_channel(chan.nam, "JOIN " + chan.nam, false);
-					if (chan.created >= cmd[1]) {
+					if (chan.created >= parseInt(cmd[1])) {
 						if (is_op) {
 							chan.modelist[CHANLIST_OP].push(member_obj.id);
 							push_sync_modes += "o";
 							push_sync_args += " " + member_obj.nick;
 							num_sync_modes++;
+							new_chan_members += "@";
 						}
 						if (num_sync_modes >= max_modes) {
 							this.bcast_to_channel(chan.nam, "MODE " + chan.nam + " " + push_sync_modes + push_sync_args);
@@ -3842,6 +3887,7 @@ function IRCClient_server_commands(origin, command, cmdline) {
 							push_sync_modes += "v";
 							push_sync_args += " " + member_obj.nick;
 							num_sync_modes++;
+							new_chan_members += "+";
 						}
 						if (num_sync_modes >= max_modes) {
 							this.bcast_to_channel(chan.nam, "MODE " + chan.nam + " " + push_sync_modes + push_sync_args);
@@ -3850,11 +3896,16 @@ function IRCClient_server_commands(origin, command, cmdline) {
 							num_sync_modes = 0;
 						}
 					}
+					new_chan_members += member_obj.nick;
 				}
 				if (num_sync_modes)
 					this.bcast_to_channel(chan.nam, "MODE " + chan.nam + " " + push_sync_modes + push_sync_args);
 
-				this.bcast_to_servers_raw(":" + servername + " SJOIN " + chan.created + " " + chan.nam + " " + chan.chanmode(true) + " :" + ircstring(cmdline))
+				// Synchronize the TS to what we received.
+				if (chan.created > parseInt(cmd[1]))
+					chan.created = parseInt(cmd[1]);
+
+				this.bcast_to_servers_raw(":" + servername + " SJOIN " + chan.created + " " + chan.nam + " " + chan.chanmode(true) + " :" + new_chan_members)
 			} else {
 				ThisOrigin.channels.push(chan.nam.toUpperCase());
 				chan.users.push(ThisOrigin.id);
@@ -3863,9 +3914,14 @@ function IRCClient_server_commands(origin, command, cmdline) {
 			}
 			break;
 		case "SQUIT":
+			var sq_server;
+
 			if (!cmd[2])
 				break;
-			var sq_server = searchbyserver(cmd[1]);
+			if (!this.hub)
+				sq_server = this;
+			else
+				sq_server = searchbyserver(cmd[1]);
 			if (!sq_server)
 				break;
 			sq_server.quit(ThisOrigin.nick + " " + sq_server.nick);
@@ -3873,24 +3929,23 @@ function IRCClient_server_commands(origin, command, cmdline) {
 		case "KILL":
 			if (!cmd[2])
 				break;
-			if (cmd[1].match(/[.]+/))
+			if (cmd[1].match(/[.]/))
 				break;
 			if (cmd[2] == ":")
 				break;
-			if (!this.hub) {
-				oper_notice("Notice","Non-Hub server " + this.nick + " trying to KILL " + cmd[1] + ", ignored and SQUITing.");
-				this.quit("Leaf servers must not global KILL.  SQUIT to avoid network desync.");
-				return 0;
-			}
 			var reason = ircstring(cmdline);
 			var kills = cmd[1].split(",");
 			for(kill in kills) {
 				var target = searchbynick(kills[kill]);
 				if (!target)
 					target = searchbynick(search_nickbuf(kills[kill]));
-				if (target) {
+				if (target && (this.hub ||
+				    (target.parent == this.id)) ) {
 					this.bcast_to_servers_raw(":" + ThisOrigin.nick + " KILL " + target.nick + " :" + reason);
 					target.quit("KILLED by " + ThisOrigin.nick + " (" + reason + ")",false);
+				} else if (target && !this.hub) {
+					oper_notice("Notice","Non-Hub server " + this.nick + " trying to KILL " + target.nick);
+					this.reintroduce_nick(target);
 				}
 			}
 			break;
@@ -3959,7 +4014,7 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				this.ircout("KILL " + cmd[1] + " :Inverse Nickname Collision.");
 				// Reintroduce our nick, because the remote end
 				// probably killed it already on our behalf.
-				this.server_nick_info(collide);
+				this.reintroduce_nick(collide);
 				break;
 			}
 			if (cmd[2][0] == ":") {
@@ -4214,9 +4269,16 @@ function IRCClient_server_commands(origin, command, cmdline) {
 			}
 			break;
 		case "AKILL":
+			var this_uh;
+
 			if (!cmd[6])
 				break;
-			var this_uh = cmd[2] + "@" + cmd[1];
+			if (!ThisOrigin.isulined) {
+				oper_notice("Notice","Non-U:Lined server " + ThisOrigin.nick + " trying to utilize AKILL.");
+				break;
+			}
+
+			this_uh = cmd[2] + "@" + cmd[1];
 			if (isklined(this_uh))
 				break;
 			KLines.push(new KLine(this_uh,ircstring(cmdline),"A"));
@@ -4285,7 +4347,6 @@ function IRCClient_work() {
 		} else if (this.conntype == TYPE_SERVER) {
 			this.server_commands(origin,command,cmdline);
 		} else {
-			log("!ERROR: Client has bogus conntype!");
 			oper_notice("Notice","Client has bogus conntype!");
 		}
 	}
-- 
GitLab