diff --git a/exec/ircd.js b/exec/ircd.js
index 6507bdc9275795089a35f960f319197729c12244..9258f030a7e837161c36f2499cb2883052786ec7 100644
--- a/exec/ircd.js
+++ b/exec/ircd.js
@@ -191,7 +191,7 @@ function parse_nline_flags(flags) {
 				nline_flags |= NLINE_CHECK_WITH_QWKMASTER;
 				break;
 			default:
-				log("!WARNING Unknown N:Line flag '" + flags[thisflag] + "' in config.");       
+				log("!WARNING Unknown N:Line flag '" + flags[thisflag] + "' in config.");
 				break;
 		}
 	}
@@ -450,19 +450,19 @@ function read_config_file() {
 	Admin1 = "";
 	Admin2 = "";
 	Admin3 = "";
-	CLines = new Array();
-	HLines = new Array();
-	ILines = new Array();
-	KLines = new Array();
-	NLines = new Array();
-	OLines = new Array();
-	PLines = new Array();
-	QLines = new Array();
-	ULines = new Array();
+	CLines = new Array;
+	HLines = new Array;
+	ILines = new Array;
+	KLines = new Array;
+	NLines = new Array;
+	OLines = new Array;
+	PLines = new Array;
+	QLines = new Array;
+	ULines = new Array;
 	diepass = "";
 	restartpass = "";
-	YLines = new Array();
-	ZLines = new Array();
+	YLines = new Array;
+	ZLines = new Array;
 	var fname="";
 	if (config_filename && config_filename.length) {
 		if(config_filename.indexOf('/')>=0 || config_filename.indexOf('\\')>=0)
@@ -2610,130 +2610,6 @@ function Channel_match_list_mask(mask) {
 	return 1; // if we made it here, we matched something.
 }
 
-function IRCClient_do_join(chan_name,join_key) {
-	if((chan_name[0] != "#") && (chan_name[0] != "&") && !this.parent) {
-		this.numeric403(chan_name);
-		return 0;
-	}
-	for (theChar in chan_name) {
-		var theChar_code = chan_name[theChar].charCodeAt(0);
-		if ((theChar_code <= 32) || (theChar_code == 44) ||
-		    (chan_name[theChar].charCodeAt(0) == 160)) {
-			if (this.local)
-				this.numeric(479, chan_name + " :Channel name contains illegal characters.");
-			return 0;
-		}
-	}
-	if (this.channels[chan_name.toUpperCase()])
-		return 0;
-	if ((true_array_len(this.channels) >= max_user_chans) && this.local) {
-		this.numeric("405", chan_name + " :You have joined too many channels.");
-		return 0;
-	}
-	var chan = chan_name.toUpperCase().slice(0,max_chanlen);
-	if (Channels[chan] != undefined) {
-		if (this.local) {
-			if ((Channels[chan].mode&CHANMODE_INVITE) &&
-			    (chan != this.invited)) {
-				this.numeric("473", Channels[chan].nam + " :Cannot join channel (+i: invite only)");
-				return 0;
-			}
-			if ((Channels[chan].mode&CHANMODE_LIMIT) &&
-			    (Channels[chan].count_users() >= Channels[chan].arg[CHANMODE_LIMIT])) {
-				this.numeric("471", Channels[chan].nam + " :Cannot join channel (+l: channel is full)");
-				return 0;
-			}
-			if ((Channels[chan].mode&CHANMODE_KEY) &&
-			    (Channels[chan].arg[CHANMODE_KEY] != join_key)) {
-				this.numeric("475", Channels[chan].nam + " :Cannot join channel (+k: key required)");
-				return 0;
-			}
-			if (Channels[chan].isbanned(this.nuh) &&
-			    (chan != this.invited) ) {
-				this.numeric("474", Channels[chan].nam + " :Cannot join channel (+b: you're banned!)");
-				return 0;
-			}
-		}
-		// add to existing channel
-		Channels[chan].users[this.id] = this;
-		var str="JOIN :" + Channels[chan].nam;
-		if (!this.local) {
-			this.bcast_to_channel(Channels[chan], str, false);
-		} else {
-			this.bcast_to_channel(Channels[chan], str, true);
-			if (Channels[chan].topic) {
-				this.numeric332(Channels[chan]);
-				this.numeric333(Channels[chan]);
-			} else {
-				this.numeric331(Channels[chan]);
-			}
-		}
-		if (chan_name[0] != "&")
-			server_bcast_to_servers(":" + this.nick + " SJOIN " + Channels[chan].created + " " + Channels[chan].nam);
-	} else {
-		// create a new channel
-		Channels[chan]=new Channel(chan);
-		Channels[chan].nam=chan_name.slice(0,max_chanlen);
-		Channels[chan].mode=CHANMODE_NONE;
-		Channels[chan].topic="";
-		Channels[chan].created=time();
-		Channels[chan].users = new Array();
-		Channels[chan].users[this.id] = this;
-		Channels[chan].modelist[CHANMODE_BAN] = new Array;
-		Channels[chan].modelist[CHANMODE_VOICE] = new Array;
-		Channels[chan].modelist[CHANMODE_OP] = new Array;
-		Channels[chan].modelist[CHANMODE_OP][this.id] = this;
-		var str="JOIN :" + chan_name;
-		this.originatorout(str,this);
-		if (chan_name[0] != "&")
-			server_bcast_to_servers(":" + servername + " SJOIN " + Channels[chan].created + " " + Channels[chan].nam + " " + Channels[chan].chanmode() + " :@" + this.nick);
-	}
-	if (this.invited.toUpperCase() == Channels[chan].nam.toUpperCase())
-		this.invited = "";
-	this.channels[chan] = Channels[chan];
-	if (!this.parent) {
-		this.names(Channels[chan]);
-		this.numeric(366, Channels[chan].nam + " :End of /NAMES list.");
-	}
-	return 1; // success
-}
-
-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;
-	}
-	chan = chan_name.toUpperCase();
-	if (Channels[chan] != undefined) {
-		if (this.channels[chan]) {
-			str = "PART " + Channels[chan].nam;
-			if (this.parent)
-				this.bcast_to_channel(Channels[chan], str, false);
-			else
-				this.bcast_to_channel(Channels[chan], str, true);
-			this.rmchan(Channels[chan]);
-			if (chan_name[0] != "&")
-				this.bcast_to_servers(str);
-		} else if (this.local) {
-			this.numeric442(chan_name);
-		}
-	} else if (this.local) {
-		this.numeric403(chan_name);
-	}
-}
-
-function IRCClient_part_all() {
-	var partingChannel;
-
-	for(thisChannel in this.channels) {
-		partingChannel=this.channels[thisChannel];
-		this.do_part(Channels[partingChannel].nam);
-	}
-}
-
 function IRCClient_get_usermode(bcast_modes) {
 	var tmp_mode = "+";
 	for (ch in USERMODE_CHAR) {
@@ -2744,319 +2620,6 @@ function IRCClient_get_usermode(bcast_modes) {
 	return tmp_mode;
 }
 
-// Yay, version 3.0 of this.set_chanmode(), eradicates any global variables.
-function ChanMode(chan,user) {
-	this.tmplist = new Array();
-	this.tmplist[CHANMODE_OP] = new Array();
-	this.tmplist[CHANMODE_OP][false] = new Array(); //deop
-	this.tmplist[CHANMODE_OP][true] = new Array(); //op
-	this.tmplist[CHANMODE_VOICE] = new Array();
-	this.tmplist[CHANMODE_VOICE][false] = new Array(); //devoice
-	this.tmplist[CHANMODE_VOICE][true] = new Array(); //voice
-	this.tmplist[CHANMODE_BAN] = new Array();
-	this.tmplist[CHANMODE_BAN][false] = new Array(); //unban
-	this.tmplist[CHANMODE_BAN][true] = new Array(); //ban
-	this.state_arg = new Array();
-	this.state_arg[CHANMODE_KEY] = "";
-	this.state_arg[CHANMODE_LIMIT] = "";
-	this.addbits = 0;
-	this.delbits = 0;
-	this.addmodes = "";
-	this.addmodeargs = "";
-	this.delmodes = "";
-	this.delmodeargs = "";
-	this.chan = chan;
-	this.user = user;
-	// Functions.
-	this.tweaktmpmodelist = ChanMode_tweaktmpmodelist;
-	this.tweaktmpmode = ChanMode_tweaktmpmode;
-	this.affect_mode_list = ChanMode_affect_mode_list;
-}
-
-function IRCClient_set_chanmode(chan,modeline,bounce_modes) {
-	if (!chan || !modeline)
-		return;
-
-	var cmode = new ChanMode(chan,this);
-
-	var cm_args = modeline.split(' ');
-
-	var add=true;
-
-	var mode_counter=0;
-	var mode_args_counter=1; // start counting at args, not the modestring
-
-	for (modechar in cm_args[0]) {
-		mode_counter++;
-		switch (cm_args[0][modechar]) {
-			case "+":
-				if (!add)
-					add=true;
-				mode_counter--;
-				break;
-			case "-":
-				if (add)
-					add=false;
-				mode_counter--;
-				break;
-			case "b":
-				if(add && (cm_args.length<=mode_args_counter)) {
-					cmode.addbits|=CHANMODE_BAN;//list bans
-					break;
-				}
-				cmode.tweaktmpmodelist(CHANMODE_BAN,add,
-					cm_args[mode_args_counter]);
-				mode_args_counter++;
-				break;
-			case "i":
-				cmode.tweaktmpmode(CHANMODE_INVITE,add);
-				break;
-			case "k":
-				if(cm_args.length > mode_args_counter) {
-					cmode.tweaktmpmode(CHANMODE_KEY,add);
-					cmode.state_arg[CHANMODE_KEY]=cm_args[mode_args_counter];
-					mode_args_counter++;
-				}
-				break;
-			case "l":
-				if (add && (cm_args.length > mode_args_counter)) {
-					cmode.tweaktmpmode(CHANMODE_LIMIT,true);
-					var regexp = "^[0-9]{1,5}$";
-					if(cm_args[mode_args_counter].match(regexp))
-						cmode.state_arg[CHANMODE_LIMIT]=cm_args[mode_args_counter];
-					mode_args_counter++;
-				} else if (!add) {
-					cmode.tweaktmpmode(CHANMODE_LIMIT,false);
-					if (cm_args.length > mode_args_counter)
-						mode_args_counter++;
-				}
-				break;
-			case "m":
-				cmode.tweaktmpmode(CHANMODE_MODERATED,add);
-				break;
-			case "n":
-				cmode.tweaktmpmode(CHANMODE_NOOUTSIDE,add);
-				break;
-			case "o":
-				if (cm_args.length <= mode_args_counter)
-					break;
-				cmode.tweaktmpmodelist(CHANMODE_OP,add,
-					cm_args[mode_args_counter]);
-				mode_args_counter++;
-				break;
-			case "p":
-				if( (add && !(chan.mode&CHANMODE_SECRET) ||
-				     (cmode.delbits&CHANMODE_SECRET) ) ||
-				    (!add) )
-					cmode.tweaktmpmode(CHANMODE_PRIVATE,add);
-				break;
-			case "s":
-				if( (add && !(chan.mode&CHANMODE_PRIVATE) ||
-				     (cmode.delbits&CHANMODE_PRIVATE) ) ||
-				    (!add) )
-					cmode.tweaktmpmode(CHANMODE_SECRET,add);
-				break;
-			case "t":
-				cmode.tweaktmpmode(CHANMODE_TOPIC,add);
-				break;
-			case "v":
-				if (cm_args.length <= mode_args_counter)
-					break;
-				cmode.tweaktmpmodelist(CHANMODE_VOICE,add,
-					cm_args[mode_args_counter]);
-				mode_args_counter++;
-				break;
-			default:
-				if ((!this.parent) && (!this.server))
-					this.numeric(472, cm_args[0][modechar] + " :is unknown mode char to me.");
-				mode_counter--;
-				break;
-		}
-		if (mode_counter == max_modes)
-			break;
-	}
-
-	// If we're bouncing modes, traverse our side of what the modes look
-	// like and remove any modes not mentioned by what was passed to the
-	// function.  Or, clear any ops, voiced members, or bans on the 'bad'
-	// side of the network sync.
-	if (bounce_modes) {
-		for (cm in MODE) {
-			if (MODE[cm].state && (chan.mode&cm) && 
-			    !(cmode.addbits&cm)) {
-				cmode.delbits |= cm;
-			} else if (MODE[cm].list && MODE[cm].isnick) {
-				for (member in chan.modelist[cm]) {
-					cmode.delmodes += MODE[cm].modechar;
-					cmode.delmodeargs += " " +
-						chan.modelist[cm][member].nick;
-					delete chan.modelist[cm][member];
-				}
-			} else if (MODE[cm].list && !MODE[cm].isnick) {
-				for (ban in chan.modelist[cm]) {
-					cmode.delmodes += MODE[cm].modechar;
-					cmode.delmodeargs += " " +
-						chan.modelist[cm][ban];
-					delete chan.modelist[cm][ban];
-					delete chan.bantime[ban];
-					delete chan.bancreator[ban];
-				}
-			}
-		}
-	}
-
-	// Now we run through all the mode toggles and construct our lists for
-	// later display.  We also play with the channel bit switches here.
-	for (cm in MODE) {
-		if (MODE[cm].state) {
-			if ((cm&CHANMODE_KEY) && (cmode.addbits&CHANMODE_KEY)&& 
-			    cmode.state_arg[cm] && chan.arg[cm] &&
-			    !this.server && !this.parent && !bounce_modes) {
-				this.numeric(467, chan.nam +
-					" :Channel key already set.");
-			} else if ((cmode.addbits&cm) && (!(chan.mode&cm) ||
-			    ((cm==CHANMODE_LIMIT)&&(chan.arg[CHANMODE_LIMIT]!=
-			     cmode.state_arg[CHANMODE_LIMIT])) ) ) {
-				cmode.addmodes += MODE[cm].modechar;
-				chan.mode |= cm;
-				if (MODE[cm].args && MODE[cm].state) {
-					cmode.addmodeargs += " " +
-						cmode.state_arg[cm];
-					chan.arg[cm] = cmode.state_arg[cm];
-				}
-			} else if ((cmode.delbits&cm) && (chan.mode&cm)) {
-				cmode.delmodes += MODE[cm].modechar;
-				chan.mode &= ~cm;
-				if (MODE[cm].args && MODE[cm].state) {
-					cmode.delmodeargs += " " +
-						cmode.state_arg[cm];
-					chan.arg[cm] = "";
-				}
-			}
-		}
-	}
-
-	// This is a special case, if +b was passed to us without arguments,
-	// we simply display a list of bans on the channel.
-	if (cmode.addbits&CHANMODE_BAN) {
-		for (the_ban in chan.modelist[CHANMODE_BAN]) {
-			this.numeric(367, chan.nam + " " + chan.modelist[CHANMODE_BAN][the_ban] + " " + chan.bancreator[the_ban] + " " + chan.bantime[the_ban]);
-		}
-		this.numeric(368, chan.nam + " :End of Channel Ban List.");
-	}
-
-	// Bans are a specialized case, sigh.
-	for (z in cmode.tmplist[CHANMODE_BAN][true]) { // +b
-		var set_ban = create_ban_mask(
-			cmode.tmplist[CHANMODE_BAN][add][z]);
-		if ((chan.count_modelist(CHANMODE_BAN) >= max_bans) &&
-		     !this.server && !this.parent) {
-			this.numeric(478, chan.nam + " " + set_ban + " :" +
-				"Cannot add ban, channel's ban list is full.");
-		} else if (set_ban && !chan.isbanned(set_ban)) {
-			cmode.addmodes += "b";
-			cmode.addmodeargs += " " + set_ban;
-			var banid = chan.modelist[CHANMODE_BAN].push(set_ban);
-			chan.bantime[banid] = time();
-			chan.bancreator[banid] = this.nuh;
-		}
-	}
-
-	for (z in cmode.tmplist[CHANMODE_BAN][false]) { // -b
-		for (ban in chan.modelist[CHANMODE_BAN]) {
-			if (cmode.tmplist[CHANMODE_BAN][false][z].toUpperCase()
-			    == chan.modelist[CHANMODE_BAN][ban].toUpperCase()) {
-				cmode.delmodes += "b";
-				cmode.delmodeargs += " " +
-					cmode.tmplist[CHANMODE_BAN][false][z];
-				delete chan.modelist[CHANMODE_BAN][ban];
-				delete chan.bantime[ban];
-				delete chan.bancreator[ban];
-			}
-		}
-	}
-
-	// Modes where we just deal with lists of nicks.
-	cmode.affect_mode_list(CHANMODE_OP);
-	cmode.affect_mode_list(CHANMODE_VOICE);
-
-	if (!cmode.addmodes && !cmode.delmodes)
-		return 0;
-
-	var final_modestr = "";
-
-	if (cmode.addmodes)
-		final_modestr += "+" + cmode.addmodes;
-	if (cmode.delmodes)
-		final_modestr += "-" + cmode.delmodes;
-	if (cmode.addmodeargs)
-		final_modestr += cmode.addmodeargs;
-	if (cmode.delmodeargs)
-		final_modestr += cmode.delmodeargs;
-
-	var final_args = final_modestr.split(' ');
-	var arg_counter = 0;
-	var mode_counter = 0;
-	var mode_output = "";
-	var f_mode_args = "";
-	for (marg in final_args[0]) {
-		switch (final_args[0][marg]) {
-			case "+":
-				mode_output += "+";
-				add = true;
-				break;
-			case "-":
-				mode_output += "-";
-				add = false;
-				break;
-			case "l":
-				if (!add) {
-					mode_counter++;
-					mode_output += final_args[0][marg];
-					break;
-				}
-			case "b": // only modes with arguments
-			case "k":
-			case "l":
-			case "o":
-			case "v":
-				arg_counter++;
-				f_mode_args += " " + final_args[arg_counter];
-			default:
-				mode_counter++;
-				mode_output += final_args[0][marg];
-				break;
-		}
-		if (mode_counter >= max_modes) {
-			var str = "MODE " + chan.nam + " " + mode_output + f_mode_args;
-			if (!this.server)
-				this.bcast_to_channel(chan, str, true);
-			else
-				this.bcast_to_channel(chan, str, false);
-			if (chan.nam[0] != "&")
-				this.bcast_to_servers(str);
-
-			if (add)
-				mode_output = "+";
-			else
-				mode_output = "-";
-			f_mode_args = "";
-		}
-	}
-
-	if (mode_output.length > 1) {
-		str = "MODE " + chan.nam + " " + mode_output + f_mode_args;
-		if (!this.server)
-			this.bcast_to_channel(chan, str, true);
-		else
-			this.bcast_to_channel(chan, str, false);
-		if (chan.nam[0] != "&")
-			this.bcast_to_servers(str);
-	}
-
-	return 1;
-}
-
 function UMode_tweak_mode(bit,add) {
 	if (add) {
 		this.add_flags |= bit;
diff --git a/exec/load/ircd_channel.js b/exec/load/ircd_channel.js
index 065322f5dde1326db56bda6832229a01e1272912..ea9f5ded800c43aea05c06774378d4706745f353 100644
--- a/exec/load/ircd_channel.js
+++ b/exec/load/ircd_channel.js
@@ -224,3 +224,440 @@ function Channel_occupants() {
 	return chan_occupants;
 }
 
+// Yay, version 3.0 of this.set_chanmode(), eradicates any global variables.
+function ChanMode(chan,user) {
+	this.tmplist = new Array();
+	this.tmplist[CHANMODE_OP] = new Array();
+	this.tmplist[CHANMODE_OP][false] = new Array(); //deop
+	this.tmplist[CHANMODE_OP][true] = new Array(); //op
+	this.tmplist[CHANMODE_VOICE] = new Array();
+	this.tmplist[CHANMODE_VOICE][false] = new Array(); //devoice
+	this.tmplist[CHANMODE_VOICE][true] = new Array(); //voice
+	this.tmplist[CHANMODE_BAN] = new Array();
+	this.tmplist[CHANMODE_BAN][false] = new Array(); //unban
+	this.tmplist[CHANMODE_BAN][true] = new Array(); //ban
+	this.state_arg = new Array();
+	this.state_arg[CHANMODE_KEY] = "";
+	this.state_arg[CHANMODE_LIMIT] = "";
+	this.addbits = 0;
+	this.delbits = 0;
+	this.addmodes = "";
+	this.addmodeargs = "";
+	this.delmodes = "";
+	this.delmodeargs = "";
+	this.chan = chan;
+	this.user = user;
+	// Functions.
+	this.tweaktmpmodelist = ChanMode_tweaktmpmodelist;
+	this.tweaktmpmode = ChanMode_tweaktmpmode;
+	this.affect_mode_list = ChanMode_affect_mode_list;
+}
+
+function IRCClient_set_chanmode(chan,modeline,bounce_modes) {
+	if (!chan || !modeline)
+		return;
+
+	var cmode = new ChanMode(chan,this);
+
+	var cm_args = modeline.split(' ');
+
+	var add=true;
+
+	var mode_counter=0;
+	var mode_args_counter=1; // start counting at args, not the modestring
+
+	for (modechar in cm_args[0]) {
+		mode_counter++;
+		switch (cm_args[0][modechar]) {
+			case "+":
+				if (!add)
+					add=true;
+				mode_counter--;
+				break;
+			case "-":
+				if (add)
+					add=false;
+				mode_counter--;
+				break;
+			case "b":
+				if(add && (cm_args.length<=mode_args_counter)) {
+					cmode.addbits|=CHANMODE_BAN;//list bans
+					break;
+				}
+				cmode.tweaktmpmodelist(CHANMODE_BAN,add,
+					cm_args[mode_args_counter]);
+				mode_args_counter++;
+				break;
+			case "i":
+				cmode.tweaktmpmode(CHANMODE_INVITE,add);
+				break;
+			case "k":
+				if(cm_args.length > mode_args_counter) {
+					cmode.tweaktmpmode(CHANMODE_KEY,add);
+					cmode.state_arg[CHANMODE_KEY]=cm_args[mode_args_counter];
+					mode_args_counter++;
+				}
+				break;
+			case "l":
+				if (add && (cm_args.length > mode_args_counter)) {
+					cmode.tweaktmpmode(CHANMODE_LIMIT,true);
+					var regexp = "^[0-9]{1,5}$";
+					if(cm_args[mode_args_counter].match(regexp))
+						cmode.state_arg[CHANMODE_LIMIT]=cm_args[mode_args_counter];
+					mode_args_counter++;
+				} else if (!add) {
+					cmode.tweaktmpmode(CHANMODE_LIMIT,false);
+					if (cm_args.length > mode_args_counter)
+						mode_args_counter++;
+				}
+				break;
+			case "m":
+				cmode.tweaktmpmode(CHANMODE_MODERATED,add);
+				break;
+			case "n":
+				cmode.tweaktmpmode(CHANMODE_NOOUTSIDE,add);
+				break;
+			case "o":
+				if (cm_args.length <= mode_args_counter)
+					break;
+				cmode.tweaktmpmodelist(CHANMODE_OP,add,
+					cm_args[mode_args_counter]);
+				mode_args_counter++;
+				break;
+			case "p":
+				if( (add && !(chan.mode&CHANMODE_SECRET) ||
+				     (cmode.delbits&CHANMODE_SECRET) ) ||
+				    (!add) )
+					cmode.tweaktmpmode(CHANMODE_PRIVATE,add);
+				break;
+			case "s":
+				if( (add && !(chan.mode&CHANMODE_PRIVATE) ||
+				     (cmode.delbits&CHANMODE_PRIVATE) ) ||
+				    (!add) )
+					cmode.tweaktmpmode(CHANMODE_SECRET,add);
+				break;
+			case "t":
+				cmode.tweaktmpmode(CHANMODE_TOPIC,add);
+				break;
+			case "v":
+				if (cm_args.length <= mode_args_counter)
+					break;
+				cmode.tweaktmpmodelist(CHANMODE_VOICE,add,
+					cm_args[mode_args_counter]);
+				mode_args_counter++;
+				break;
+			default:
+				if ((!this.parent) && (!this.server))
+					this.numeric(472, cm_args[0][modechar] + " :is unknown mode char to me.");
+				mode_counter--;
+				break;
+		}
+		if (mode_counter == max_modes)
+			break;
+	}
+
+	// If we're bouncing modes, traverse our side of what the modes look
+	// like and remove any modes not mentioned by what was passed to the
+	// function.  Or, clear any ops, voiced members, or bans on the 'bad'
+	// side of the network sync.
+	if (bounce_modes) {
+		for (cm in MODE) {
+			if (MODE[cm].state && (chan.mode&cm) && 
+			    !(cmode.addbits&cm)) {
+				cmode.delbits |= cm;
+			} else if (MODE[cm].list && MODE[cm].isnick) {
+				for (member in chan.modelist[cm]) {
+					cmode.delmodes += MODE[cm].modechar;
+					cmode.delmodeargs += " " +
+						chan.modelist[cm][member].nick;
+					delete chan.modelist[cm][member];
+				}
+			} else if (MODE[cm].list && !MODE[cm].isnick) {
+				for (ban in chan.modelist[cm]) {
+					cmode.delmodes += MODE[cm].modechar;
+					cmode.delmodeargs += " " +
+						chan.modelist[cm][ban];
+					delete chan.modelist[cm][ban];
+					delete chan.bantime[ban];
+					delete chan.bancreator[ban];
+				}
+			}
+		}
+	}
+
+	// Now we run through all the mode toggles and construct our lists for
+	// later display.  We also play with the channel bit switches here.
+	for (cm in MODE) {
+		if (MODE[cm].state) {
+			if ((cm&CHANMODE_KEY) && (cmode.addbits&CHANMODE_KEY)&& 
+			    cmode.state_arg[cm] && chan.arg[cm] &&
+			    !this.server && !this.parent && !bounce_modes) {
+				this.numeric(467, chan.nam +
+					" :Channel key already set.");
+			} else if ((cmode.addbits&cm) && (!(chan.mode&cm) ||
+			    ((cm==CHANMODE_LIMIT)&&(chan.arg[CHANMODE_LIMIT]!=
+			     cmode.state_arg[CHANMODE_LIMIT])) ) ) {
+				cmode.addmodes += MODE[cm].modechar;
+				chan.mode |= cm;
+				if (MODE[cm].args && MODE[cm].state) {
+					cmode.addmodeargs += " " +
+						cmode.state_arg[cm];
+					chan.arg[cm] = cmode.state_arg[cm];
+				}
+			} else if ((cmode.delbits&cm) && (chan.mode&cm)) {
+				cmode.delmodes += MODE[cm].modechar;
+				chan.mode &= ~cm;
+				if (MODE[cm].args && MODE[cm].state) {
+					cmode.delmodeargs += " " +
+						cmode.state_arg[cm];
+					chan.arg[cm] = "";
+				}
+			}
+		}
+	}
+
+	// This is a special case, if +b was passed to us without arguments,
+	// we simply display a list of bans on the channel.
+	if (cmode.addbits&CHANMODE_BAN) {
+		for (the_ban in chan.modelist[CHANMODE_BAN]) {
+			this.numeric(367, chan.nam + " " + chan.modelist[CHANMODE_BAN][the_ban] + " " + chan.bancreator[the_ban] + " " + chan.bantime[the_ban]);
+		}
+		this.numeric(368, chan.nam + " :End of Channel Ban List.");
+	}
+
+	// Bans are a specialized case, sigh.
+	for (z in cmode.tmplist[CHANMODE_BAN][true]) { // +b
+		var set_ban = create_ban_mask(
+			cmode.tmplist[CHANMODE_BAN][add][z]);
+		if ((chan.count_modelist(CHANMODE_BAN) >= max_bans) &&
+		     !this.server && !this.parent) {
+			this.numeric(478, chan.nam + " " + set_ban + " :" +
+				"Cannot add ban, channel's ban list is full.");
+		} else if (set_ban && !chan.isbanned(set_ban)) {
+			cmode.addmodes += "b";
+			cmode.addmodeargs += " " + set_ban;
+			var banid = chan.modelist[CHANMODE_BAN].push(set_ban);
+			chan.bantime[banid] = time();
+			chan.bancreator[banid] = this.nuh;
+		}
+	}
+
+	for (z in cmode.tmplist[CHANMODE_BAN][false]) { // -b
+		for (ban in chan.modelist[CHANMODE_BAN]) {
+			if (cmode.tmplist[CHANMODE_BAN][false][z].toUpperCase()
+			    == chan.modelist[CHANMODE_BAN][ban].toUpperCase()) {
+				cmode.delmodes += "b";
+				cmode.delmodeargs += " " +
+					cmode.tmplist[CHANMODE_BAN][false][z];
+				delete chan.modelist[CHANMODE_BAN][ban];
+				delete chan.bantime[ban];
+				delete chan.bancreator[ban];
+			}
+		}
+	}
+
+	// Modes where we just deal with lists of nicks.
+	cmode.affect_mode_list(CHANMODE_OP);
+	cmode.affect_mode_list(CHANMODE_VOICE);
+
+	if (!cmode.addmodes && !cmode.delmodes)
+		return 0;
+
+	var final_modestr = "";
+
+	if (cmode.addmodes)
+		final_modestr += "+" + cmode.addmodes;
+	if (cmode.delmodes)
+		final_modestr += "-" + cmode.delmodes;
+	if (cmode.addmodeargs)
+		final_modestr += cmode.addmodeargs;
+	if (cmode.delmodeargs)
+		final_modestr += cmode.delmodeargs;
+
+	var final_args = final_modestr.split(' ');
+	var arg_counter = 0;
+	var mode_counter = 0;
+	var mode_output = "";
+	var f_mode_args = "";
+	for (marg in final_args[0]) {
+		switch (final_args[0][marg]) {
+			case "+":
+				mode_output += "+";
+				add = true;
+				break;
+			case "-":
+				mode_output += "-";
+				add = false;
+				break;
+			case "l":
+				if (!add) {
+					mode_counter++;
+					mode_output += final_args[0][marg];
+					break;
+				}
+			case "b": // only modes with arguments
+			case "k":
+			case "l":
+			case "o":
+			case "v":
+				arg_counter++;
+				f_mode_args += " " + final_args[arg_counter];
+			default:
+				mode_counter++;
+				mode_output += final_args[0][marg];
+				break;
+		}
+		if (mode_counter >= max_modes) {
+			var str = "MODE " + chan.nam + " " + mode_output + f_mode_args;
+			if (!this.server)
+				this.bcast_to_channel(chan, str, true);
+			else
+				this.bcast_to_channel(chan, str, false);
+			if (chan.nam[0] != "&")
+				this.bcast_to_servers(str);
+
+			if (add)
+				mode_output = "+";
+			else
+				mode_output = "-";
+			f_mode_args = "";
+		}
+	}
+
+	if (mode_output.length > 1) {
+		str = "MODE " + chan.nam + " " + mode_output + f_mode_args;
+		if (!this.server)
+			this.bcast_to_channel(chan, str, true);
+		else
+			this.bcast_to_channel(chan, str, false);
+		if (chan.nam[0] != "&")
+			this.bcast_to_servers(str);
+	}
+
+	return 1;
+}
+
+function IRCClient_do_join(chan_name,join_key) {
+	if((chan_name[0] != "#") && (chan_name[0] != "&") && !this.parent) {
+		this.numeric403(chan_name);
+		return 0;
+	}
+	for (theChar in chan_name) {
+		var theChar_code = chan_name[theChar].charCodeAt(0);
+		if ((theChar_code <= 32) || (theChar_code == 44) ||
+		    (chan_name[theChar].charCodeAt(0) == 160)) {
+			if (this.local)
+				this.numeric(479, chan_name + " :Channel name contains illegal characters.");
+			return 0;
+		}
+	}
+	if (this.channels[chan_name.toUpperCase()])
+		return 0;
+	if ((true_array_len(this.channels) >= max_user_chans) && this.local) {
+		this.numeric("405", chan_name + " :You have joined too many channels.");
+		return 0;
+	}
+	var chan = chan_name.toUpperCase().slice(0,max_chanlen);
+	if (Channels[chan] != undefined) {
+		if (this.local) {
+			if ((Channels[chan].mode&CHANMODE_INVITE) &&
+			    (chan != this.invited)) {
+				this.numeric("473", Channels[chan].nam + " :Cannot join channel (+i: invite only)");
+				return 0;
+			}
+			if ((Channels[chan].mode&CHANMODE_LIMIT) &&
+			    (Channels[chan].count_users() >= Channels[chan].arg[CHANMODE_LIMIT])) {
+				this.numeric("471", Channels[chan].nam + " :Cannot join channel (+l: channel is full)");
+				return 0;
+			}
+			if ((Channels[chan].mode&CHANMODE_KEY) &&
+			    (Channels[chan].arg[CHANMODE_KEY] != join_key)) {
+				this.numeric("475", Channels[chan].nam + " :Cannot join channel (+k: key required)");
+				return 0;
+			}
+			if (Channels[chan].isbanned(this.nuh) &&
+			    (chan != this.invited) ) {
+				this.numeric("474", Channels[chan].nam + " :Cannot join channel (+b: you're banned!)");
+				return 0;
+			}
+		}
+		// add to existing channel
+		Channels[chan].users[this.id] = this;
+		var str="JOIN :" + Channels[chan].nam;
+		if (!this.local) {
+			this.bcast_to_channel(Channels[chan], str, false);
+		} else {
+			this.bcast_to_channel(Channels[chan], str, true);
+			if (Channels[chan].topic) {
+				this.numeric332(Channels[chan]);
+				this.numeric333(Channels[chan]);
+			} else {
+				this.numeric331(Channels[chan]);
+			}
+		}
+		if (chan_name[0] != "&")
+			server_bcast_to_servers(":" + this.nick + " SJOIN " + Channels[chan].created + " " + Channels[chan].nam);
+	} else {
+		// create a new channel
+		Channels[chan]=new Channel(chan);
+		Channels[chan].nam=chan_name.slice(0,max_chanlen);
+		Channels[chan].mode=CHANMODE_NONE;
+		Channels[chan].topic="";
+		Channels[chan].created=time();
+		Channels[chan].users = new Array();
+		Channels[chan].users[this.id] = this;
+		Channels[chan].modelist[CHANMODE_BAN] = new Array;
+		Channels[chan].modelist[CHANMODE_VOICE] = new Array;
+		Channels[chan].modelist[CHANMODE_OP] = new Array;
+		Channels[chan].modelist[CHANMODE_OP][this.id] = this;
+		var str="JOIN :" + chan_name;
+		this.originatorout(str,this);
+		if (chan_name[0] != "&")
+			server_bcast_to_servers(":" + servername + " SJOIN " + Channels[chan].created + " " + Channels[chan].nam + " " + Channels[chan].chanmode() + " :@" + this.nick);
+	}
+	if (this.invited.toUpperCase() == Channels[chan].nam.toUpperCase())
+		this.invited = "";
+	this.channels[chan] = Channels[chan];
+	if (!this.parent) {
+		this.names(Channels[chan]);
+		this.numeric(366, Channels[chan].nam + " :End of /NAMES list.");
+	}
+	return 1; // success
+}
+
+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;
+	}
+	chan = chan_name.toUpperCase();
+	if (Channels[chan] != undefined) {
+		if (this.channels[chan]) {
+			str = "PART " + Channels[chan].nam;
+			if (this.parent)
+				this.bcast_to_channel(Channels[chan], str, false);
+			else
+				this.bcast_to_channel(Channels[chan], str, true);
+			this.rmchan(Channels[chan]);
+			if (chan_name[0] != "&")
+				this.bcast_to_servers(str);
+		} else if (this.local) {
+			this.numeric442(chan_name);
+		}
+	} else if (this.local) {
+		this.numeric403(chan_name);
+	}
+}
+
+function IRCClient_part_all() {
+	var partingChannel;
+
+	for(thisChannel in this.channels) {
+		partingChannel=this.channels[thisChannel];
+		this.do_part(Channels[partingChannel].nam);
+	}
+}
+