diff --git a/exec/ircd.js b/exec/ircd.js
index 026d3aca8beaf4f889f2112dad8800b09052c48c..bdad8e6bf484485811082bed4b025848dca3b977 100644
--- a/exec/ircd.js
+++ b/exec/ircd.js
@@ -175,20 +175,24 @@ var OLINE_CAN_DEBUG		=(1<<21);	// x
 // Various N:Line permission bits
 var NLINE_CHECK_QWKPASSWD	=(1<<0);	// q
 var NLINE_CAN_CLINE		=(1<<1);	// c
-var NLINE_IS_TIMEMASTER		=(1<<2);	// t
 
 ////////// Functions not linked to an object //////////
-function ip_to_dec(ip) {
-	quads = ip.split(".");
-	addr=(quads[0]&0xff)<<24;
+function ip_to_int(ip) {
+	var quads = ip.split(".");
+	var addr = (quads[0]&0xff)<<24;
 	addr|=(quads[1]&0xff)<<16;
 	addr|=(quads[2]&0xff)<<8;
 	addr|=(quads[3]&0xff);
 	return addr;
 }
 
-function dec_to_ip(ip) {
-	// TODO XXX :)
+function int_to_ip(ip) {
+	return(format("%u.%u.%u.%u"
+		,(ip>>24)&0xff
+		,(ip>>16)&0xff
+		,(ip>>8)&0xff
+		,ip&0xff
+		));
 }
 
 function terminate_everything(terminate_reason) {
@@ -299,14 +303,12 @@ function parse_nline_flags(flags) {
 			case "c":
 				nline_flags |= NLINE_CAN_CLINE;
 				break;
-			case "t":
-				nline_flags |= NLINE_IS_TIMEMASTER;
-				break;
 			default:
 				log("!WARNING Unknown N:Line flag '" + flags[thisflag] + "' in config.");       
 				break;
 		}
 	}
+	return nline_flags;
 }
 
 function parse_oline_flags(flags) {
@@ -368,6 +370,7 @@ function parse_oline_flags(flags) {
 				oline_flags |= OLINE_CHECK_SYSPASSWD;
 				break;
 			case "x":
+			case "X":
 				oline_flags |= OLINE_CAN_DEBUG;
 				break;
 			case "O":
@@ -493,6 +496,8 @@ function scan_for_klined_clients() {
 			    (theuser.conntype == TYPE_USER)) {
 				if (isklined(theuser.uprefix + "@" + theuser.hostname))
 					theuser.quit("User has been K:Lined (" + KLines[thiskl].reason + ")");
+				if (iszlined(theuser.ip))
+					theuser.quit("User has been Z:Lined");
 			}
 		}
 	}
@@ -682,6 +687,7 @@ function read_config_file() {
 	Admin2 = "";
 	Admin3 = "";
 	CLines = new Array();
+	HLines = new Array();
 	ILines = new Array();
 	KLines = new Array();
 	NLines = new Array();
@@ -733,6 +739,11 @@ function read_config_file() {
 							break;
 						CLines.push(new CLine(arg[1],arg[2],arg[3],arg[4],arg[5]));
 						break;
+					case "H":
+						if (!arg[3])
+							break;
+						HLines.push(new HLine(arg[1],arg[3]));
+						break;
 					case "I":
 						if (!arg[5])
 							break;
@@ -758,7 +769,7 @@ function read_config_file() {
 					case "N":
 						if (!arg[5])
 							break;
-						NLines.push(new NLine(arg[1],arg[2],arg[3],arg[4],arg[5]));
+						NLines.push(new NLine(arg[1],arg[2],arg[3],parse_nline_flags(arg[4]),arg[5]));
 						break;
 					case "O":
 						if (!arg[5])
@@ -808,8 +819,8 @@ function read_config_file() {
 }
 
 function create_new_socket(port) {
-	var newsock = new Socket();
 	log("Creating new socket object on port " + port);
+	var newsock = new Socket();
 	if(!newsock.bind(port)) {
 		log("!Error " + newsock.error + " binding socket to TCP port " + port);
 		return 0;
@@ -837,6 +848,7 @@ Channels = new Array;
 hcc_total = 0;
 hcc_users = 0;
 hcc_counter = 0;
+time_offset = 0;
 server_uptime = time();
 
 WhoWasHistory = new Array;
@@ -956,7 +968,7 @@ function IRCClient(socket,new_id,local_client,do_newconn) {
 	this.hostname = "";
 	this.conntype = TYPE_UNREGISTERED;
 	this.ircclass = 0;
-	this.operflags = 0;
+	this.flags = 0;
 	this.idletime = "";
 	this.invited = "";
 	this.password = "";
@@ -980,6 +992,7 @@ function IRCClient(socket,new_id,local_client,do_newconn) {
 	};
 	this.hops=0;
 	this.server=false;
+	this.hub=false;
 	this.servername = servername;
 	this.affect_mode_list=IRCClient_affect_mode_list;
 	this.tweaktmpmode=IRCClient_tweaktmpmode;
@@ -1038,7 +1051,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.decip=0;
+	this.ip="";
 	this.linkparent="";
 	if (this.socket && local_client && do_newconn) {
 		log(format("%04u",this.socket.descriptor)
@@ -1070,7 +1083,7 @@ function IRCClient(socket,new_id,local_client,do_newconn) {
 			}
 		}
 		if (this.socket.remote_ip_address)
-			this.decip = ip_to_dec(this.socket.remote_ip_address);
+			this.ip = this.socket.remote_ip_address;
 		this.connecttime = time();
 		this.idletime = time();
 		this.talkidle = time();
@@ -1110,7 +1123,7 @@ function IRCClient_Quit(str,do_bcast) {
 
 	if (this.local) {
 		this.rawout("ERROR :Closing Link: [" + this.uprefix + "@" + this.hostname + "] (" + str + ")");
-		oper_notice("Notice","Client exiting: " + this.nick + " (" + this.uprefix + "@" + this.hostname + ") [" + str + "] [" + this.decip + "]");
+		oper_notice("Notice","Client exiting: " + this.nick + " (" + this.uprefix + "@" + this.hostname + ") [" + str + "] [" + this.ip + "]");
 		this.socket.close();
 	}
 
@@ -1156,8 +1169,8 @@ function IRCClient_synchronize() {
 	oper_notice("Routing","from " + servername + ": " + this.nick + " has processed user/channel burst, sending topic burst.");
 	for (my_channel in Channels) {
 		if ((my_channel[0] == "#") && Channels[my_channel].topic) {
-			chan = Channels[my_channel];
-			this.rawout("TOPIC " + chan.nam + " " + servername + " " + chan.topictime + " :" + chan.topic);
+			var chan = Channels[my_channel];
+			this.rawout("TOPIC " + chan.nam + " " + chan.topicchangedby + " " + chan.topictime + " :" + chan.topic);
 		}
 	}
 	this.rawout("BURST 0"); // burst completed.
@@ -1170,14 +1183,14 @@ function IRCClient_server_info(sni_server) {
 }
 
 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 + " " + sni_client.decip + " 0 :" + sni_client.realname);
+	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_server_chan_info(sni_chan) {
-	this.ircout("SJOIN " + sni_chan.created + " " + sni_chan.nam + " " + sni_chan.chanmode(true) + " :" + sni_chan.occupants())
-	modecounter=0;
-	modestr="+";
-	modeargs="";
+	this.rawout("SJOIN " + sni_chan.created + " " + sni_chan.nam + " " + sni_chan.chanmode(true) + " :" + sni_chan.occupants())
+	var modecounter=0;
+	var modestr="+";
+	var modeargs="";
 	for (aBan in sni_chan.modelist[CHANLIST_BAN]) {
 		modecounter++;
 		modestr += "b";
@@ -1193,8 +1206,6 @@ function IRCClient_server_chan_info(sni_chan) {
 	}
 	if (modeargs)
 		this.ircout("MODE " + sni_chan.nam + " " + modestr + " " + modeargs);
-	if (sni_chan.topic)
-		this.ircout("TOPIC " + sni_chan.nam + " rrx.ca " + sni_chan.topictime + " :" + sni_chan.topic);
 }
 
 function IRCClient_RMChan(rmchan_obj) {
@@ -1499,8 +1510,8 @@ function IRCClient_bcast_to_channel(chan_str, str, bounce) {
 }
 
 function IRCClient_bcast_to_channel_servers(chan_str, str) {
-	sent_to_servers = new Array();
-	chan_tuc = chan_str.toUpperCase();
+	var sent_to_servers = new Array();
+	var chan_tuc = chan_str.toUpperCase();
 	if (Channels[chan_tuc] != undefined) {
 		for(thisUser in Channels[chan_tuc].users) {
 			aUser=Channels[chan_tuc].users[thisUser];
@@ -1512,7 +1523,6 @@ function IRCClient_bcast_to_channel_servers(chan_str, str) {
 			}
 		}
 	}
-	delete sent_to_servers;
 }
 
 function IRCClient_check_nickname(newnick) {
@@ -1523,12 +1533,14 @@ function IRCClient_check_nickname(newnick) {
 	// First, check for valid characters.
 	regexp="^[A-Za-z\{\}\`\^\_\|\\]\\[\\\\][A-Za-z0-9\-\{\}\`\^\_\|\\]\\[\\\\]*$";
 	if(!newnick.match(regexp)) {
-		this.numeric("432", newnick + " :Foobar'd Nickname.");
+		if (!this.server)
+			this.numeric("432", newnick + " :Foobar'd Nickname.");
 		return 0;
 	}
 	// Second, check for existing nickname.
 	if(searchbynick(newnick)) {
-		this.numeric("433", newnick + " :Nickname is already in use.");
+		if (!this.server)
+			this.numeric("433", newnick + " :Nickname is already in use.");
 		return 0;
 	}
 	// Third, match against Q:Lines
@@ -1538,7 +1550,8 @@ function IRCClient_check_nickname(newnick) {
 		qline_nick = qline_nick.replace(/[*]/g,".*?");
 		regexp = new RegExp("^" + qline_nick + "$","i");
 		if(newnick.match(regexp)) {
-			this.numeric(432, newnick + " :" + QLines[ql].reason);
+			if (!this.server)
+				this.numeric(432, newnick + " :" + QLines[ql].reason);
 			return 0;
 		}
 	}
@@ -1549,7 +1562,7 @@ function IRCClient_do_whois(wi) {
 	if (!wi)
 		return 0;
 	this.numeric(311, wi.nick + " " + wi.uprefix + " " + wi.hostname + " * :" + wi.realname);
-	userchans="";
+	var userchans="";
 	for (i in wi.channels) {
 		if(wi.channels[i] &&
 		   (!(Channels[wi.channels[i]].mode&CHANMODE_SECRET ||
@@ -2121,7 +2134,8 @@ function IRCClient_setusermode(modestr) {
 				break;
 			case "o":
 				// Allow +o only by servers or non-local users.
-				if (add && (this.parent)) {
+				if (add && (this.parent) &&
+				    Clients[this.parent].hub) {
 					addbits|=USERMODE_OPER;
 					delbits&=~USERMODE_OPER;
 				}
@@ -2246,9 +2260,7 @@ function IRCClient_unregistered_commands(command, cmdline) {
 				this.numeric461(command);
 				break;
 			}
-			if (cmd[1][0] == ":")
-				cmd[1] = cmd[1].slice(1);
-			this.ircout("PONG " + servername + " :" + cmd[1]);
+			this.ircout("PONG " + servername + " :" + ircstring(cmdline));
 			break;
 		case "PONG":
 			this.pinged = false;
@@ -2262,31 +2274,49 @@ function IRCClient_unregistered_commands(command, cmdline) {
 				this.numeric461("SERVER");
 				break;
 			}
-			this_nline = "";
+			var this_nline = 0;
 			for (nl in NLines) {
 				if ((NLines[nl].password == this.password) &&
 				    (NLines[nl].servername == cmd[1])) {
 					this_nline = NLines[nl];
 					break;
+				} else if ((NLines[nl].flags&NLINE_CHECK_QWKPASSWD) &&
+				           match_irc_mask(cmd[1],NLines[nl].servername)) {
+					var qwkid = cmd[1].slice(0,cmd[1].indexOf(".")).toUpperCase();
+					var usernum = system.matchuser(qwkid);
+					var bbsuser = new User(usernum);
+					if ((this.password.toUpperCase() ==
+					    bbsuser.security.password) &&
+					    (bbsuser.security.restrictions&UFLAG_Q)
+					   ) {
+						this_nline = NLines[nl];
+						break;
+					}
 				}
 			}
 			if (!this_nline) {
-				this.rawout("ERROR :Server not configured.");
 				this.quit("ERROR: Server not configured.");
 				return 0;
 			}
 			if (searchbyserver(cmd[1])) {
-				this.rawout("ERROR :Server already exists.");
 				this.quit("ERROR: Server already exists.");
 				return 0;
 			}
-			this.nick = cmd[1];
+			this.nick = cmd[1].toLowerCase();
 			this.hops = cmd[2];
 			this.realname = ircstring(cmdline);
 			this.server = true;
 			this.conntype = TYPE_SERVER;
 			this.linkparent = servername;
 			this.parent = this.id;
+			this.flags = this_nline.flags;
+			for (hl in HLines) {
+				if (HLines[hl].servername.toUpperCase() ==
+				    this.nick.toUpperCase()) {
+					this.hub = true;
+					break;
+				}
+			}
 			break;
 		case "USER":
 			if (this.server) {
@@ -2313,7 +2343,8 @@ function IRCClient_unregistered_commands(command, cmdline) {
 		this.quit("You've been K:Lined from this server.");
 		return 0;
 	}
-	if (this.password && (unreg_username || (this.nick != "*"))) {
+	if (this.password && (unreg_username || (this.nick != "*")) &&
+	    !this.server) {
 		if (unreg_username)
 			var usernum = system.matchuser(unreg_username);
 		if (!usernum && (this.nick != "*"))
@@ -2328,7 +2359,8 @@ function IRCClient_unregistered_commands(command, cmdline) {
 		hcc_total = count_local_nicks() + count_servers(false);
 	if (count_local_nicks() > hcc_users)
 		hcc_users = count_local_nicks();
-	if (this.realname && this.uprefix && (this.nick != "*")) {
+	if (this.realname && this.uprefix && (this.nick != "*") &&
+	    !this.server) {
 		// Check for a valid I:Line.
 		this.ircclass = this.searchbyiline();
 		if (!this.ircclass) {
@@ -2348,7 +2380,8 @@ function IRCClient_unregistered_commands(command, cmdline) {
 		oper_notice("Notice","Client connecting: " + this.nick + " (" + this.uprefix + "@" + this.hostname + ") [" + this.socket.remote_ip_address + "] {1}");
 		if (server.client_update != undefined)
 			server.client_update(this.socket, this.nick, this.hostname);
-		server_bcast_to_servers("NICK " + this.nick + " 1 " + this.created + " " + this.get_usermode() + " " + this.uprefix + " " + this.hostname + " " + servername + " " + this.decip + " 0 :" + this.realname);
+		server_bcast_to_servers("NICK " + this.nick + " 1 " + this.created + " " + this.get_usermode() + " " + this.uprefix + " " + this.hostname + " " + servername + " 0 " + ip_to_int(this.ip) + " :" + this.realname);
+	/// Otherwise, it's a server trying to connect.
 	} else if (this.nick.match("[.]") && this.hops && this.realname &&
 		   this.server && (this.conntype == TYPE_SERVER)) {
 		hcc_counter++;
@@ -2432,7 +2465,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			break;
 		case "DEBUG":
 			if (!((this.mode&USERMODE_OPER) &&
-			      (this.operflags&OLINE_CAN_DEBUG))) {
+			      (this.flags&OLINE_CAN_DEBUG))) {
 				this.numeric481();
 				break;
 			}
@@ -2466,7 +2499,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			break;
 		case "EVAL":	/* Evaluate a JavaScript expression */
 			if (!((this.mode&USERMODE_OPER) &&
-			      (this.operflags&OLINE_CAN_DEBUG))) {
+			      (this.flags&OLINE_CAN_DEBUG))) {
 				this.numeric481();
 				break;
 			}
@@ -2647,7 +2680,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			break;
 		case "KLINE":
 			if (!((this.mode&USERMODE_OPER) &&
-			      (this.operflags&OLINE_CAN_KLINE))) {
+			      (this.flags&OLINE_CAN_KLINE))) {
 				this.numeric481();
 				break;
 			}
@@ -2670,7 +2703,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			break;
 		case "UNKLINE":
 			if (!((this.mode&USERMODE_OPER) &&
-			      (this.operflags&OLINE_CAN_UNKLINE))) {
+			      (this.flags&OLINE_CAN_UNKLINE))) {
 				this.numeric481();
 				break;
 			}
@@ -2864,7 +2897,7 @@ function IRCClient_registered_commands(command, cmdline) {
 				))) {
 					oper_success=true;
 					this.ircclass = OLines[ol].ircclass;
-					this.operflags = OLines[ol].flags;
+					this.flags = OLines[ol].flags;
 					break;
 				}
 			}
@@ -2927,7 +2960,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			break;
 		case "DIE":
 			if (!((this.mode&USERMODE_OPER) &&
-			      (this.operflags&OLINE_CAN_DIE))) {
+			      (this.flags&OLINE_CAN_DIE))) {
 				this.numeric481();
 				break;
 			}
@@ -2943,7 +2976,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			break;
 		case "REHASH":
 			if (!((this.mode&USERMODE_OPER) &&
-			      (this.operflags&OLINE_CAN_REHASH))) {
+			      (this.flags&OLINE_CAN_REHASH))) {
 				this.numeric481();
 				break;
 			}
@@ -2954,7 +2987,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			break;
 		case "RESTART":
 			if (!((this.mode&USERMODE_OPER) &&
-			      (this.operflags&OLINE_CAN_RESTART))) {
+			      (this.flags&OLINE_CAN_RESTART))) {
 				this.numeric481();
 				break;
 			}
@@ -3108,7 +3141,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			}
 			break;
 		case "TIME":
-			this.numeric(391, servername + " :" + strftime("%A %B %e %Y -- %H:%M %z",time()));
+			this.numeric(391, servername + " :" + strftime("%A %B %d %Y -- %H:%M %z",time()));
 			break;
 		case "TOPIC":
 			if (!cmd[1]) {
@@ -3127,13 +3160,13 @@ function IRCClient_registered_commands(command, cmdline) {
 			if (cmd[2]) {
 				if (!(chanid.mode&CHANMODE_TOPIC) ||
 				     chanid.ismode(this.id,CHANLIST_OP) ) {
-					tmp_topic = ircstring(cmdline).slice(0,max_topiclen);
+					var tmp_topic = ircstring(cmdline).slice(0,max_topiclen);
 					if (tmp_topic == chanid.topic)
 						break;
 					chanid.topic = tmp_topic;
 					chanid.topictime = time();
 					chanid.topicchangedby = this.nick;
-					str = "TOPIC " + chanid.nam + " :" + chanid.topic;
+					var str = "TOPIC " + chanid.nam + " :" + chanid.topic;
 					this.bcast_to_channel(chanid.nam.toUpperCase(), str, true);
 					this.bcast_to_servers("TOPIC " + chanid.nam + " " + this.nick + " " + chanid.topictime + " :" + chanid.topic);
 				} else {
@@ -3200,7 +3233,7 @@ function IRCClient_registered_commands(command, cmdline) {
 			break;
 		case "LOCOPS":
 			if (!((this.mode&USERMODE_OPER) &&
-			      (this.operflags&OLINE_CAN_LOCOPS))) {
+			      (this.flags&OLINE_CAN_LOCOPS))) {
 				this.numeric481();
 				break;
 			}
@@ -3363,11 +3396,14 @@ function IRCClient_registered_commands(command, cmdline) {
 
 // Server connections are ConnType 5
 function IRCClient_server_commands(origin, command, cmdline) {
-	ThisOrigin = searchbynick(origin);
+	var ThisOrigin = searchbyserver(origin);
 	if (!ThisOrigin)
-		ThisOrigin = searchbyserver(origin);
-	if (!ThisOrigin)
-		ThisOrigin = this;
+		ThisOrigin = searchbynick(origin);
+	if (!ThisOrigin) { // FIXME: SQUIT if it looks like a server prefix.
+		oper_notice("Notice","Server " + this.nick + " trying to pass message for non-existent origin " + origin);
+		this.rawout("KILL " + origin + " :" + servername + " (" + origin + "(?) <- " + this.nick + ")");
+		return 0;
+	}
 
 	cmd=cmdline.split(' ');
 
@@ -3558,10 +3594,15 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				break;
 			if (cmd[2] == ":")
 				break;
-			reason = ircstring(cmdline);
-			kills = cmd[1].split(",");
+			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) {
-				target = searchbynick(kills[kill]);
+				var target = searchbynick(kills[kill]);
 				if (!target)
 					target = searchbynick(search_nickbuf(kills[kill]));
 				if (target) {
@@ -3582,29 +3623,35 @@ function IRCClient_server_commands(origin, command, cmdline) {
 					cmdline += cmd[xx];
 				}
 			}
-			if (cmd[1][0] == "#")
-				chan = searchbychannel(cmd[1])
+			if (cmd[1][0] == "#") {
+				var chan = searchbychannel(cmd[1])
 				if (!chan)
 					break;
 				var modeline = cmdline.slice(cmdline.indexOf(" ")+1);
 				var modeline = modeline.slice(modeline.indexOf(" ")+1);
 				ThisOrigin.set_chanmode(chan,modeline,false);
+			} else { // assume it's for a user
+				ThisOrigin.setusermode(cmd[2]);
+			}
 			break;
 		case "NICK":
 			if (!cmd[8] && (cmd[2][0] != ":"))
 				break;
-			collide = searchbynick(cmd[1]);
-			if ((collide) && (parseInt(collide.created) <
-			    parseInt(cmd[3]) ) ) {
-				// FIXME: At the moment, we rely on the remote
-				// end to do the right thing.
-				break;
-			} else if ((collide) && (parseInt(collide.created) >
-			    parseInt(cmd[3]) ) ) {
+			var collide = searchbynick(cmd[1]);
+			if ((collide) && (parseInt(collide.created) >
+			    parseInt(cmd[3]) ) && this.hub) {
 				// Nuke our side of things, allow this newly
 				// introduced nick to overrule.
 				this.bcast_to_servers("KILL " + collide.nick + " :Nickname Collision.");
 				collide.quit("Nickname Collision");
+			} else if (collide && !this.hub) {
+				oper_notice("Notice","Server " + this.nick + " trying to collide nick " + collide.nick + " forwards, reversing.");
+				// Don't collide our side of things from a leaf
+				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);
+				break;
 			}
 			if (cmd[2][0] == ":") {
 				cmd[2] = cmd[2].slice(1);
@@ -3614,6 +3661,16 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				push_nickbuf(ThisOrigin.nick,cmd[1]);
 				ThisOrigin.nick = cmd[1];
 			} else if (cmd[10]) {
+				if (!this.hub) {
+					if(!this.check_nickname(cmd[1])) {
+						oper_notice("Notice","Server " + this.nick + " trying to introduce invalid nickname: " + cmd[1] + ", killed.");
+						this.ircout("KILL " + cmd[1] + " :Bogus Nickname.");
+						break;
+					}
+					cmd[2] = 1; // Force hops to 1.
+					cmd[3] = time(); // Force TS on nick.
+					cmd[7] = this.nick // Force server name
+				}
 				new_id = get_next_clientid();
 				Clients[new_id]=new IRCClient(-1,new_id,false,true);
 				NewNick = Clients[new_id];
@@ -3631,10 +3688,10 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				NewNick.idletime = 0;
 				NewNick.talkidle = 0;
 				NewNick.parent = this.id;
-				NewNick.decip = cmd[9];
+				NewNick.ip = int_to_ip(cmd[9]);
 				NewNick.setusermode(cmd[4]);
 				true_hops = parseInt(NewNick.hops)+1;
-				this.bcast_to_servers_raw("NICK " + NewNick.nick + " " + true_hops + " " + NewNick.created + " " + NewNick.get_usermode() + " " + NewNick.uprefix + " " + NewNick.hostname + " " + NewNick.servername + " 0 " + NewNick.decip + " :" + NewNick.realname);
+				this.bcast_to_servers_raw("NICK " + NewNick.nick + " " + true_hops + " " + NewNick.created + " " + NewNick.get_usermode() + " " + NewNick.uprefix + " " + NewNick.hostname + " " + NewNick.servername + " 0 " + cmd[9] + " :" + NewNick.realname);
 			}
 			break;
 		case "NOTICE":
@@ -3672,13 +3729,10 @@ function IRCClient_server_commands(origin, command, cmdline) {
 			}
 			break;
 		case "PING":
-			if (!cmd[1]) {
+			if (!cmd[1])
 				break;
-			} else {
-				if (cmd[1][0] == ":")
-					cmd[1] = cmd[1].slice(1);
-				this.ircout("PONG " + servername + " :" + cmd[1]);              
-			}                                                       
+			else
+				this.ircout("PONG " + servername + " :" + ircstring(cmdline));              
 			break;
 		case "PONG":
 			this.pinged = false;
@@ -3697,16 +3751,22 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				this.parent = this.id;
 				newsrv = this;
 			} else if (parseInt(cmd[2]) > 1) {
-				new_id = get_next_clientid();
-				Clients[new_id] = new IRCClient(-1,new_id,false,false);
-				newsrv = Clients[new_id];
-				newsrv.hops = cmd[2];
-				newsrv.nick = cmd[1];
-				newsrv.realname = ircstring(cmdline);
-				newsrv.server = true;
-				newsrv.parent = this.id;
-				newsrv.conntype = TYPE_SERVER;
-				newsrv.linkparent = ThisOrigin.nick;
+				if (this.hub) {
+					new_id = get_next_clientid();
+					Clients[new_id] = new IRCClient(-1,new_id,false,false);
+					newsrv = Clients[new_id];
+					newsrv.hops = cmd[2];
+					newsrv.nick = cmd[1];
+					newsrv.realname = ircstring(cmdline);
+					newsrv.server = true;
+					newsrv.parent = this.id;
+					newsrv.conntype = TYPE_SERVER;
+					newsrv.linkparent = ThisOrigin.nick;
+				} else {
+					oper_notice("Routing","from " + servername + ": Non-Hub link " + this.nick + " introduced " + cmd[1] + "(*).");
+					this.quit("Too many servers.  You have no H:Line to introduce " + cmd[1] + ".");
+					return 0;
+				}
 			} else {
 				break;
 			}
@@ -3715,11 +3775,17 @@ function IRCClient_server_commands(origin, command, cmdline) {
 		case "TOPIC":
 			if (!cmd[4])
 				break;
-			chan = searchbychannel(cmd[1]);
+			var chan = searchbychannel(cmd[1]);
 			if (!chan)
 				break;
-			chan.topic = ircstring(cmdline);
-			chan.topictime = cmd[3];
+			if (the_topic == chan.topic)
+				break;
+			var the_topic = ircstring(cmdline);
+			chan.topic = the_topic;
+			if (this.hub)
+				chan.topictime = cmd[3];
+			else
+				chan.topictime = time();
 			chan.topicchangedby = cmd[2];
 			str = "TOPIC " + chan.nam + " :" + chan.topic;
 			ThisOrigin.bcast_to_channel(chan.nam,str,false);
@@ -3790,15 +3856,15 @@ function IRCClient_work() {
 				return 0;
 			// if :<originator> doesn't match nick of originating
 			// socket, drop silently per RFC.
-			origin = cmd[0].slice(1);
+			var origin = cmd[0].slice(1);
 			if ((this.conntype == TYPE_USER) &&
 			    (origin.toUpperCase() != this.nick.toUpperCase()))
 				return 0;
-			command = cmd[1].toUpperCase();
+			var command = cmd[1].toUpperCase();
 			cmdline = cmdline.slice(cmdline.indexOf(" ")+1);
 		} else {
 			command = cmd[0].toUpperCase();
-			origin = this.nick;
+			var origin = this.nick;
 		}
 
 		this.idletime = time();
@@ -3995,6 +4061,11 @@ function CLine(host,password,servername,port,ircclass) {
 	this.lastconnect = 0;
 }
 
+function HLine(allowedmask,servername) {
+	this.allowedmask = allowedmask;
+	this.servername = servername;
+}
+
 function ILine(ipmask,password,hostmask,port,ircclass) {
 	this.ipmask = ipmask;
 	this.password = password;