diff --git a/exec/ircd.js b/exec/ircd.js
index 08576cc5b9ac816781d3b8e975e85a597706c7e5..842bb374017fbb31846e9a709eae0c6f6fac7b54 100644
--- a/exec/ircd.js
+++ b/exec/ircd.js
@@ -145,6 +145,8 @@ function dec_to_ip(ip) {
 }
 
 function searchbynick(nick) {
+	if (!nick)
+		return 0;
 	for(thisClient in Clients) {
 		Client=Clients[thisClient];
 		if ((nick.toUpperCase() == Client.nick.toUpperCase()) &&
@@ -165,13 +167,24 @@ function searchbychannel(chan) {
 }
 
 function searchbyserver(server_name) {
+	if (!server_name)
+		return 0;
+	if (match_irc_mask(servername,server_name))
+		return -1; // the server passed to us is our own.
 	for(thisServer in Clients) {
 		Server=Clients[thisServer];
-		if ((server_name.toUpperCase() == Server.nick.toUpperCase()) &&
-		    (Server.conntype == TYPE_SERVER) )
+		if ( (Server.conntype == TYPE_SERVER) &&
+		     match_irc_mask(Server.nick,server_name) )
 			return Server;
 	}
-	return 0;
+	// if we've had no success so far, try nicknames and glean a server
+	// from there.
+	for(thisNick in Clients) {
+		Nick=Clients[thisNick];
+		if (!Nick.server && match_irc_mask(Nick.nick,server_name))
+			return searchbyserver(Nick.servername);
+	}
+	return 0; // looks like we failed after all that hard work :(
 }
 
 // IRC is funky.  A "string" in IRC is anything after a :, and anything before
@@ -204,6 +217,7 @@ function parse_username(str) {
 
 function server_wallops(str) {
 	wallopers(":" + servername + " WALLOPS :" + str);
+	server_bcast_to_servers(":" + servername + " WALLOPS :" + str);
 }
 
 function create_ban_mask(str,kline) {
@@ -268,7 +282,7 @@ function match_irc_mask(mtchstr,mask) {
 	mask=mask.replace(/[?]/g,".");
 	mask=mask.replace(/[*]/g,".*?");
 	final_mask=final_mask + mask + "$";
-	return mtchstr.match(final_mask);
+	return mtchstr.toUpperCase().match(final_mask.toUpperCase());
 }
 
 function isklined(kl_str) {
@@ -336,6 +350,33 @@ function wallopers(str) {
 	}
 }
 
+function push_nickbuf(oldnick,newnick) {
+	NickHistory[nick_pointer] = new NickBuf(oldnick,newnick);
+	nick_pointer++;
+	if(nick_pointer == nick_buffer)
+		nick_pointer = 0;
+}
+
+function search_nickbuf(bufnick) {
+	for (nb=nick_pointer;nb>=0;nb--) {
+		if (NickHistory[nb] && (bufnick.toUpperCase() == NickHistory[nb].oldnick.toUpperCase())) {
+			if (!searchbynick(NickHistory[nb].newnick))
+				return search_nickbuf(NickHistory[nb].newnick);
+			else
+				return NickHistory[nb].newnick;
+		}
+	}
+	for (nb=nick_buffer;nb>=nick_pointer;nb--) {
+		if (NickHistory[nb] && (bufnick.toUpperCase() == NickHistory[nb].oldnick.toUpperCase())) {
+			if (!searchbynick(NickHistory[nb].newnick))
+				return search_nickbuf(NickHistory[nb].newnick);
+			else
+				return NickHistory[nb].newnick;
+		}
+	}
+	return 0;
+}
+
 function IRCClient_tweaktmpmode(tmp_bit) {
 	if ((!chan.ismode(this.id,CHANLIST_OP)) && (!this.server) && (!this.parent)) {
 		this.numeric482(chan.nam);
@@ -479,75 +520,75 @@ function read_config_file() {
 	}
 	conf = new File(fname);
 	if (conf.open("r")) {
-		log("Reading " + fname);
+		log("Reading Config: " + fname);
 		while (!conf.eof) {
 			conf_line = conf.readln();
-			if (conf_line == null)
-				break;
-			arg = conf_line.split(":");
-			for(argument in arg) {
-				arg[argument]=arg[argument].replace(
-					/SYSTEM_HOST_NAME/g,system.host_name);
-				arg[argument]=arg[argument].replace(
-					/SYSTEM_NAME/g,system.name);
-				arg[argument]=arg[argument].replace(
-					/SYSTEM_QWKID/g,system.qwk_id.toLowerCase());
-				arg[argument]=arg[argument].replace(
-					/VERSION_NOTICE/g,system.version_notice);
-			}
-			switch (conf_line[0].toUpperCase()) {
-				case "A":
-					if (!arg[3])
+			if ((conf_line != null) && conf_line.match("[:]")) {
+				arg = conf_line.split(":");
+				for(argument in arg) {
+					arg[argument]=arg[argument].replace(
+						/SYSTEM_HOST_NAME/g,system.host_name);
+					arg[argument]=arg[argument].replace(
+						/SYSTEM_NAME/g,system.name);
+					arg[argument]=arg[argument].replace(
+						/SYSTEM_QWKID/g,system.qwk_id.toLowerCase());
+					arg[argument]=arg[argument].replace(
+						/VERSION_NOTICE/g,system.version_notice);
+				}
+				switch (conf_line[0].toUpperCase()) {
+					case "A":
+						if (!arg[3])
+							break;
+						Admin1 = arg[1];
+						Admin2 = arg[2];
+						Admin3 = arg[3];
 						break;
-					Admin1 = arg[1];
-					Admin2 = arg[2];
-					Admin3 = arg[3];
-					break;
-				case "C":
-					if (!arg[5])
+					case "C":
+						if (!arg[5])
+							break;
+						CLines.push(new CLine(arg[1],arg[2],arg[3],arg[4],arg[5]));
 						break;
-					CLines.push(new CLine(arg[1],arg[2],arg[3],arg[4],arg[5]));
-					break;
-				case "K":
-					if (!arg[2])
+					case "K":
+						if (!arg[2])
+							break;
+						kline_mask = create_ban_mask(arg[1],true);
+						if (!kline_mask) {
+							log("!WARNING Invalid K:Line (" + arg[1] + ")");
+							break;
+						}
+						KLines.push(new KLine(kline_mask,arg[2],"K"));
 						break;
-					kline_mask = create_ban_mask(arg[1],true);
-					if (!kline_mask) {
-						log("!WARNING Invalid K:Line (" + arg[1] + ")");
+					case "M":
+						if (!arg[3])
+							break;
+						servername = arg[1];
+						serverdesc = arg[3];
 						break;
-					}
-					KLines.push(new KLine(kline_mask,arg[2],"K"));
-					break;
-				case "M":
-					if (!arg[3])
+					case "N":
+						if (!arg[5])
+							break;
+						NLines.push(new NLine(arg[1],arg[2],arg[3],arg[4],arg[5]));
 						break;
-					servername = arg[1];
-					serverdesc = arg[3];
-					break;
-				case "N":
-					if (!arg[5])
+					case "O":
+						if (!arg[5])
+							break;
+						OLines.push(new OLine(arg[1],arg[2],arg[3],arg[4],arg[5]));
 						break;
-					NLines.push(new NLine(arg[1],arg[2],arg[3],arg[4],arg[5]));
-					break;
-				case "O":
-					if (!arg[5])
+					case "Q":
+						if (!arg[3])
+							break;
+						QLines.push(new QLine(arg[3],arg[2]));
 						break;
-					OLines.push(new OLine(arg[1],arg[2],arg[3],arg[4],arg[5]));
-					break;
-				case "Q":
-					if (!arg[3])
+					case "U":
+						if (!arg[1])
+							break;
+						ULines.push(arg[1]);
 						break;
-					QLines.push(new QLine(arg[3],arg[2]));
-					break;
-				case "U":
-					if (!arg[1])
+					case "#":
+					case ";":
+					default:
 						break;
-					ULines.push(arg[1]);
-					break;
-				case "#":
-				case ";":
-				default:
-					break;
+				}
 			}
 		}
 		conf.close();
@@ -575,6 +616,7 @@ hcc_counter = 0;
 server_uptime = time();
 
 WhoWasHistory = new Array;
+NickHistory = new Array;
 whowas_buffer = 10000;
 whowas_pointer = 0;
 nick_buffer = 10000;
@@ -589,7 +631,6 @@ for (cmdarg=0;cmdarg<argc;cmdarg++) {
 	}
 }
 
-log("Reading config file...");
 read_config_file();
 log("Synchronet IRC Daemon (" + version + ") started.");
 
@@ -672,6 +713,7 @@ function IRCClient(socket,new_id,local_client,do_newconn) {
 	this.server_notice=IRCClient_server_notice;
 	this.setusermode=IRCClient_setusermode;
 	this.numeric=IRCClient_numeric;
+	this.numeric351=IRCClient_numeric351;
 	this.numeric353=IRCClient_numeric353;
 	this.numeric401=IRCClient_numeric401;
 	this.numeric402=IRCClient_numeric402;
@@ -720,7 +762,6 @@ function IRCClient(socket,new_id,local_client,do_newconn) {
 		log(format("%04u",this.socket.descriptor)
 			+ " Accepted new connection: " + this.socket.remote_ip_address
 			+ " port " + this.socket.remote_port);
-		log("Accepted new connection: " + this.socket.remote_ip_address + " port " + this.socket.remote_port);
 		this.nick = "*";
 		this.realname = "";
 		this.away = "";
@@ -943,6 +984,10 @@ function IRCClient_numeric(num, str) {
 }
 
 //////////////////// Numeric Functions ////////////////////
+function IRCClient_numeric351() {
+	this.numeric(351, version + " " + servername + " :Synchronet IRC Daemon by Randy Sommerfeld <sysop@rrx.ca>");
+}
+
 function IRCClient_numeric353(chan, str) {
 	// = public @ secret * everything else
 	if (Channels[chan].mode&CHANMODE_SECRET)
@@ -1244,6 +1289,26 @@ function IRCClient_do_whois(wi) {
 }
 
 function IRCClient_do_msg(target,type_str,send_str) {
+	if ((target[0] == "$") && (this.mode&USERMODE_OPER)) {
+		var global_mask = target.slice(1);
+		var global_str = type_str + " " + target + " :" + send_str;
+		for(globClient in Clients) {
+			var Client = Clients[globClient];
+			if ((Client.conntype == TYPE_USER) &&
+			    match_irc_mask(Client.servername,global_mask) &&
+			    Client.local)
+				Client.originatorout(global_str,this);
+		}
+		global_str = ":" + this.nick + " " + global_str;
+		if(this.parent) {
+			var globServer = Clients[this.parent];
+			globServer.bcast_to_servers_raw(global_str);
+		} else {
+			server_bcast_to_servers(global_str);
+		}
+		return 1;
+	}
+
 	send_to_list = -1;
 	if (target[0] == "@" && ( (target[1] == "#") || target[1] == "&") ) {
 		send_to_list = CHANLIST_OP;
@@ -1252,6 +1317,7 @@ function IRCClient_do_msg(target,type_str,send_str) {
 		send_to_list = CHANLIST_VOICE;
 		target = target.slice(1);
 	}
+		
 	if ((target[0] == "#") || (target[0] == "&")) {
 		chan = searchbychannel(target);
 		if (!chan) {
@@ -1799,20 +1865,20 @@ function IRCClient_setusermode(modestr) {
 function IRCClient_affect_mode_list(tmp_add,list_bit) {
 	for (tmp_index in chan_tmplist[list_bit]) {
 		tmp_nick = searchbynick(chan_tmplist[list_bit][tmp_index]);
-		tmp_nickid = tmp_nick.id;
-		if (tmp_nickid) {
-			if (tmp_add && (!chan.ismode(tmp_nickid,list_bit))) {
+		if (!tmp_nick)
+			tmp_nick = searchbynick(search_nickbuf(chan_tmplist[list_bit][tmp_index]));
+		if (tmp_nick) { // FIXME: check for user existing on channel?
+			if (tmp_add && (!chan.ismode(tmp_nick.id,list_bit))) {
 				addmodes += const_modechar[list_bit];
 				addmodeargs += " " + tmp_nick.nick;
-				chan.add_modelist(tmp_nickid,list_bit);
-			} else if (chan.ismode(tmp_nickid,list_bit-1)) {
+				chan.add_modelist(tmp_nick.id,list_bit);
+			} else if (chan.ismode(tmp_nick.id,list_bit-1)) {
 				delmodes += const_modechar[list_bit];
 				delmodeargs += " " + tmp_nick.nick;
-				chan.del_modelist(tmp_nickid,list_bit-1);
+				chan.del_modelist(tmp_nick.id,list_bit-1);
 			}
 		} else {
 			this.numeric401(chan_tmplist[list_bit][tmp_index]);
-			this.numeric441(cm_cmd[1]);
 		}
 	}
 }
@@ -1821,6 +1887,8 @@ function IRCClient_affect_mode_list(tmp_add,list_bit) {
 
 // Unregistered users are ConnType 1
 function IRCClient_unregistered_commands(command, cmdline) {
+	if (command.match(/^[0-9]+/))
+		return 0; // we ignore all numerics from unregistered clients.
 	cmd=cmdline.split(' ');
 	switch(command) {
 		case "CAPAB":
@@ -1884,6 +1952,7 @@ function IRCClient_unregistered_commands(command, cmdline) {
 			this.server = true;
 			this.conntype = TYPE_SERVER;
 			this.linkparent = servername;
+			this.parent = this.id;
 			break;
 		case "USER":
 			if (this.server) {
@@ -1895,7 +1964,8 @@ function IRCClient_unregistered_commands(command, cmdline) {
 				break;
 			}
 			this.realname = ircstring(cmdline).slice(0,50);
-			this.uprefix = "~" + parse_username(cmd[1]);
+			var unreg_username = parse_username(cmd[1]);
+			this.uprefix = "~" + unreg_username;
 			break;
 		case "QUIT":
 			this.quit(ircstring(cmdline),true);
@@ -1909,6 +1979,17 @@ 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 (unreg_username)
+			var usernum = system.matchuser(unreg_username);
+		if (!usernum && (this.nick != "*"))
+			var usernum = system.matchuser(this.nick);
+		if (usernum) {
+			bbsuser = new User(usernum);
+			if (this.password.toUpperCase() == bbsuser.security.password)
+				this.uprefix = parse_username(bbsuser.handle).toLowerCase().slice(0,10);
+		}
+	}
 	if ( (count_local_nicks() + count_servers(false)) > hcc_total)
 		hcc_total = count_local_nicks() + count_servers(false);
 	if (count_local_nicks() > hcc_users)
@@ -1952,6 +2033,8 @@ function IRCClient_unregistered_commands(command, cmdline) {
 
 // Registered users are ConnType 2
 function IRCClient_registered_commands(command, cmdline) {
+	if (command.match(/^[0-9]+/))
+		return 0; // ignore numerics from clients.
 	cmd=cmdline.split(' ');
 	switch(command) {
 		case "ADMIN":
@@ -2137,8 +2220,11 @@ function IRCClient_registered_commands(command, cmdline) {
 			}
 			nickid = searchbynick(cmd[2]);
 			if (!nickid) {
-				this.numeric401(cmd[2]);
-				break;
+				nickid = searchbynick(search_nickbuf(cmd[2]));
+				if (!nickid) {
+					this.numeric401(cmd[2]);
+					break;
+				}
 			}
 			if (!nickid.onchannel(chanid.nam.toUpperCase())) {
 				this.numeric("441", nickid.nick + " " + chanid.nam + " :They aren't on that channel!");
@@ -2174,6 +2260,8 @@ function IRCClient_registered_commands(command, cmdline) {
 			kills = cmd[1].split(",");
 			for(kill in kills) {
 				target = searchbynick(kills[kill]);
+				if (!target)
+					target = searchbynick(search_nickbuf(kills[kill]));
 				if (target) {
 					server_wallops("/KILL: " + this.nick + " -> " + target.nick + " (" + reason + ")");
 					server_bcast_to_servers(":" + this.nick + " KILL " + target.nick + " :" + reason);
@@ -2349,7 +2437,9 @@ function IRCClient_registered_commands(command, cmdline) {
 				str="NICK " + the_nick;
 				this.bcast_to_uchans_unique(str);
 				this.originatorout(str,this);
-				this.bcast_to_servers(str + " :" + time());
+				this.created = time();
+				this.bcast_to_servers(str + " :" + this.created);
+				push_nickbuf(this.nick,the_nick);
 				this.nick = the_nick;
 			}
 			break;
@@ -2455,7 +2545,9 @@ function IRCClient_registered_commands(command, cmdline) {
 				this.numeric481();
 				break;
 			}
-			this.server_notice("DIE isn't implemented yet.  Sorry.");
+			log("!ERROR! Shutting down the ircd as per " + this.ircnuh);
+			server_wallops("!ERROR! Shutting down the ircd as per " + this.ircnuh);
+			terminated = true;
 			break;
 		case "REHASH":
 			if (!(this.mode&USERMODE_OPER)) {
@@ -2490,6 +2582,10 @@ function IRCClient_registered_commands(command, cmdline) {
 			reason = ircstring(cmdline);
 			if (!reason)
 				reason = this.nick;
+			if (sq_server == -1) {
+				this.quit(reason);
+				break;
+			}
 			server_wallops("SQUIT for " + cmd[1] + " issued by " + this.ircnuh);
 			sq_server.quit(ircstring(cmdline));
 			break;
@@ -2675,7 +2771,20 @@ function IRCClient_registered_commands(command, cmdline) {
 				this.numeric("302", ":");
 			break;
 		case "VERSION":
-			this.numeric("351", version + " " + servername + " :Synchronet IRC Daemon by Randy Sommerfeld <sysop@rrx.ca>");
+			if (cmd[1]) {
+				if (cmd[1][0] == ":")
+					cmd[1] = cmd[1].slice(1);
+				var dest_server = searchbyserver(cmd[1]);
+				if (!dest_server) {
+					this.numeric402(cmd[1]);
+					break;
+				}
+				if (dest_server != -1) {
+					dest_server.rawout(":" + this.nick + " VERSION :" + dest_server.nick);
+					break;
+				}
+			}
+			this.numeric351();
 			break;
 		case "GLOBOPS":
 		case "WALLOPS":
@@ -2685,6 +2794,7 @@ function IRCClient_registered_commands(command, cmdline) {
 				break;
 			}
 			wallopers(":" + this.ircnuh + " WALLOPS :" + ircstring(cmdline));
+			server_bcast_to_servers(":" + this.nick + " WALLOPS :" + ircstring(cmdline));
 			break;
 		case "WHO":
 			if (!cmd[1]) {
@@ -2780,7 +2890,19 @@ function IRCClient_server_commands(origin, command, cmdline) {
 		ThisOrigin = searchbyserver(origin);
 	if (!ThisOrigin)
 		ThisOrigin = this;
+
 	cmd=cmdline.split(' ');
+
+	if (command.match(/^[0-9]+/)) { // passing on a numeric to the client
+		if (!cmd[1])
+			return 0; // uh...?
+		var destination = searchbynick(cmd[1]);
+		if (!destination)
+			return 0;
+		destination.rawout(":" + ThisOrigin.nick + " " + cmdline);
+		return 1;
+	}
+
 	switch(command) {
 		case "GNOTICE":
 		case "GLOBOPS":
@@ -2808,6 +2930,8 @@ function IRCClient_server_commands(origin, command, cmdline) {
 			if (!chanid)
 				break;
 			nickid = searchbynick(cmd[2]);
+			if (!nickid)
+				nickid = searchbynick(search_nickbuf(cmd[2]));
 			if (!nickid)
 				break;
 			if (!nickid.onchannel(chanid.nam.toUpperCase()))
@@ -2934,6 +3058,8 @@ function IRCClient_server_commands(origin, command, cmdline) {
 			kills = cmd[1].split(",");
 			for(kill in kills) {
 				target = searchbynick(kills[kill]);
+				if (!target)
+					target = searchbynick(search_nickbuf(kills[kill]));
 				if (target) {
 					this.bcast_to_servers_raw(":" + ThisOrigin.nick + " KILL " + target.nick + " :" + reason);
 					target.quit("KILLED by " + ThisOrigin.nick + " (" + reason + ")",false);
@@ -2959,12 +3085,12 @@ function IRCClient_server_commands(origin, command, cmdline) {
 			if (!cmd[8] && (cmd[2][0] != ":"))
 				break;
 			collide = searchbynick(cmd[1]);
-			if ((collide) && (parseInt(collide.connecttime) <
+			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.connecttime) >
+			} else if ((collide) && (parseInt(collide.created) >
 			    parseInt(cmd[3]) ) ) {
 				// Nuke our side of things, allow this newly
 				// introduced nick to overrule.
@@ -2976,6 +3102,7 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				ThisOrigin.created = cmd[2];
 				ThisOrigin.bcast_to_uchans_unique("NICK " + cmd[1]);
 				this.bcast_to_servers_raw(":" + origin + " NICK " + cmd[1] + " :" + cmd[2]);
+				push_nickbuf(ThisOrigin.nick,cmd[1]);
 				ThisOrigin.nick = cmd[1];
 			} else if (cmd[10]) {
 				new_id = get_next_clientid();
@@ -2991,7 +3118,7 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				NewNick.conntype = TYPE_USER_REMOTE;
 				NewNick.away = "";
 				NewNick.mode = USERMODE_NONE;
-				NewNick.connecttime = time(); // BROKEN XXX FIXME
+				NewNick.connecttime = 0;
 				NewNick.idletime = 0;
 				NewNick.talkidle = 0;
 				NewNick.parent = this.id;
@@ -3058,6 +3185,7 @@ function IRCClient_server_commands(origin, command, cmdline) {
 				this.hops = 1;
 				this.realname = ircstring(cmdline);
 				this.linkparent = servername;
+				this.parent = this.id;
 				newsrv = this;
 			} else if (parseInt(cmd[2]) > 1) {
 				new_id = get_next_clientid();
@@ -3082,10 +3210,27 @@ function IRCClient_server_commands(origin, command, cmdline) {
 			if (!chan)
 				break;
 			chan.topic = ircstring(cmdline);
-			chan.topictime = cmd[2];
-			chan.topicchangedby = cmd[1];
+			chan.topictime = cmd[3];
+			chan.topicchangedby = cmd[2];
 			str = "TOPIC " + chan.nam + " :" + chan.topic;
-			this.bcast_to_channel(chan.nam,str,false);
+			ThisOrigin.bcast_to_channel(chan.nam,str,false);
+			this.bcast_to_servers_raw(":" + ThisOrigin.nick + " TOPIC " + chan.nam + " " + ThisOrigin.nick + " " + chan.topictime + " :" + chan.topic);
+			break;
+		case "VERSION":
+			if (!cmd[1])
+				break;
+			if (cmd[1][0] == ":")
+				cmd[1] = cmd[1].slice(1);
+			if (match_irc_mask(servername, cmd[1])) {
+				// it's for us, return the message
+				ThisOrigin.numeric351();
+			} else {
+				// psst, pass it on
+				var dest_server = searchbyserver(cmd[1]);
+				if (!dest_server)
+					break; // someone messed up.
+				dest_server.rawout(":" + ThisOrigin.nick + " VERSION :" + dest_server.nick);
+			}
 			break;
 		case "AKILL":
 			if (!cmd[6])
@@ -3147,9 +3292,6 @@ function IRCClient_work() {
 			origin = this.nick;
 		}
 
-		if (!this.server && (command.match(/^[0-9]+/)))
-			return 0; // possible numeric from user, ignore per RFC
-
 		this.idletime = time();
 		if (this.conntype == TYPE_UNREGISTERED) {
 			this.unregistered_commands(command,cmdline);
@@ -3377,3 +3519,7 @@ function WhoWas(nick,uprefix,host,realname,server,serverdesc) {
 	this.serverdesc = serverdesc;
 }
 
+function NickBuf(oldnick,newnick) {
+	this.oldnick = oldnick;
+	this.newnick = newnick;
+}