General tidying up!
authorJack Allnutt <m2ys4u@Gmail.com>
Sun, 31 Jul 2011 09:01:24 +0000 (10:01 +0100)
committerJack Allnutt <m2ys4u@Gmail.com>
Sun, 31 Jul 2011 09:01:24 +0000 (10:01 +0100)
Front.js now (almost) passes jslint, although it still uses eval() and possibly leaks global variables.

Fix for new message sending.

js/front.js
js/gateway.js
node/kiwi.js
node/kiwi_modules/statistics.js
node/lib/kiwi_mod.js

index d09087d70cafcbbd708a41031231e1909ce0a5b5..223422bf296e31705592e87940231877c0c50ae3 100644 (file)
+/*jslint undef: true, browser: true, continue: true, sloppy: true, evil: true, forin: true, newcap: false, plusplus: true, maxerr: 50, indent: 4 */
+/*global gateway, io, $, iScroll, agent, touchscreen*/
 var front = {
-       revision: 38,
-       
-       cur_channel: '',
-       windows: {},
-       tabviews: {},
-       boxes: {},
-       
-       buffer: [],
-       buffer_pos: 0,
+    revision: 38,
+    
+    cur_channel: '',
+    windows: {},
+    tabviews: {},
+    boxes: {},
+    
+    buffer: [],
+    buffer_pos: 0,
 
     original_topic: '',
-       
-       init: function () {     
-               gateway.nick = 'kiwi_' + Math.ceil(100 * Math.random()) + Math.ceil(100 * Math.random());
-               gateway.session_id = null;
-               
-               $(gateway).bind("onmsg", front.onMsg);
-               $(gateway).bind("onnotice", front.onNotice);
-               $(gateway).bind("onaction", front.onAction);
-               $(gateway).bind("onmotd", front.onMOTD);
-               $(gateway).bind("onoptions", front.onOptions);
-               $(gateway).bind("onconnect", front.onConnect);
-               $(gateway).bind("ondisconnect", front.onDisconnect);
-               $(gateway).bind("onnick", front.onNick);
-               $(gateway).bind("onuserlist", front.onUserList);
-               $(gateway).bind("onuserlist_end", front.onUserListEnd);
-               $(gateway).bind("onjoin", front.onJoin);
-               $(gateway).bind("ontopic", front.onTopic);
-               $(gateway).bind("onpart", front.onPart);
-               $(gateway).bind("onkick", front.onKick);
-               $(gateway).bind("onquit", front.onQuit);
-               $(gateway).bind("onwhois", front.onWhois);
-               $(gateway).bind("onsync", front.onSync);
-               $(gateway).bind("onchannel_redirect", front.onChannelRedirect);
-               $(gateway).bind("ondebug", front.onDebug);
+    
+    init: function () {
+        var about_info, supportsOrientationChange, orientationEvent;
+        gateway.nick = 'kiwi_' + Math.ceil(100 * Math.random()) + Math.ceil(100 * Math.random());
+        gateway.session_id = null;
+        
+        $(gateway).bind("onmsg", front.onMsg);
+        $(gateway).bind("onnotice", front.onNotice);
+        $(gateway).bind("onaction", front.onAction);
+        $(gateway).bind("onmotd", front.onMOTD);
+        $(gateway).bind("onoptions", front.onOptions);
+        $(gateway).bind("onconnect", front.onConnect);
+        $(gateway).bind("ondisconnect", front.onDisconnect);
+        $(gateway).bind("onnick", front.onNick);
+        $(gateway).bind("onuserlist", front.onUserList);
+        $(gateway).bind("onuserlist_end", front.onUserListEnd);
+        $(gateway).bind("onjoin", front.onJoin);
+        $(gateway).bind("ontopic", front.onTopic);
+        $(gateway).bind("onpart", front.onPart);
+        $(gateway).bind("onkick", front.onKick);
+        $(gateway).bind("onquit", front.onQuit);
+        $(gateway).bind("onwhois", front.onWhois);
+        $(gateway).bind("onsync", front.onSync);
+        $(gateway).bind("onchannel_redirect", front.onChannelRedirect);
+        $(gateway).bind("ondebug", front.onDebug);
         $(gateway).bind("onctcp_request", front.onCTCPRequest);
         $(gateway).bind("onctcp_response", front.onCTCPResponse);
         $(gateway).bind("onirc_error", front.onIRCError);
-               
-               this.buffer = [];
-               
-               // Build the about box
-               front.boxes.about = new box("about");
-               var about_info = 'UI adapted for ' + agent;
-               if (touchscreen) about_info += ' touchscreen ';
-               about_info += 'usage';
-               $('#tmpl_about_box').tmpl({
-                       about:about_info,
-                       front_revision:front.revision,
-                       gateway_revision:gateway.revision
-               }).appendTo(front.boxes.about.content);
-
-               //$(window).bind("beforeunload", function(){ gateway.quit(); });
-               
-               if(touchscreen){
-                       $('#kiwi').addClass('touchscreen');
-
-                       // Single touch scrolling through scrollback for touchscreens
-                       scroll_opts = {};
-                       touch_scroll = new iScroll('windows', scroll_opts);
-               }
-
-               front.registerKeys();
-               
-               $('#kiwi .cur_topic').resize(front.doLayoutSize);
-
-               $('#kiwi .formconnectwindow').submit(function () {
-                       var netsel = $('#kiwi .formconnectwindow .network');
-                       var nick = $('#kiwi .formconnectwindow .nick');
-                       
-                       if (nick.val() === '') {
-                               nick.val('Nick please!');
-                               nick.focus();
-                               return false;
-                       }
-                       
-                       var tmp = nick.val().split(' ');
-                       gateway.nick = tmp[0];
-                       front.doLayout();
-                       try {
-                               front.run('/connect ' + netsel.val());
-                       } catch (e) {
-                               alert(e);
-                       }
-                       
-                       $('#kiwi .connectwindow').slideUp();
-                       $('#windows').click(function(){ $('#kiwi_msginput').focus(); });
-
-                       return false;
-               });
-
-               var supportsOrientationChange = "onorientationchange" in window,
-                   orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";
-               window.addEventListener(orientationEvent, front.doLayoutSize, false);
-               //$('#kiwi').bind("resize", front.doLayoutSize, false);
-
-               front.doLayout();
-               //front.windowAdd('server');
-               front.tabviewAdd('server');
-               
-               // Any pre-defined nick?
-               if (typeof init_data.nick === "string") {
+        
+        this.buffer = [];
+        
+        // Build the about box
+        front.boxes.about = new Box("about");
+        about_info = 'UI adapted for ' + agent;
+        if (touchscreen) {
+            about_info += ' touchscreen ';
+        }
+        about_info += 'usage';
+        $('#tmpl_about_box').tmpl({
+            about: about_info,
+            front_revision: front.revision,
+            gateway_revision: gateway.revision
+        }).appendTo(front.boxes.about.content);
+
+        //$(window).bind("beforeunload", function(){ gateway.quit(); });
+        
+        if (touchscreen) {
+            $('#kiwi').addClass('touchscreen');
+
+            // Single touch scrolling through scrollback for touchscreens
+            scroll_opts = {};
+            touch_scroll = new iScroll('windows', scroll_opts);
+        }
+
+        front.registerKeys();
+        
+        $('#kiwi .cur_topic').resize(front.doLayoutSize);
+
+        $('#kiwi .formconnectwindow').submit(function () {
+            var netsel = $('#kiwi .formconnectwindow .network'),
+                nick = $('#kiwi .formconnectwindow .nick'),
+                tmp;
+            
+            if (nick.val() === '') {
+                nick.val('Nick please!');
+                nick.focus();
+                return false;
+            }
+            
+            tmp = nick.val().split(' ');
+            gateway.nick = tmp[0];
+            front.doLayout();
+            try {
+                front.run('/connect ' + netsel.val());
+            } catch (e) {
+                alert(e);
+            }
+            
+            $('#kiwi .connectwindow').slideUp();
+            $('#windows').click(function () { $('#kiwi_msginput').focus(); });
+
+            return false;
+        });
+
+        supportsOrientationChange = (typeof window.onorientationchange !==  undefined);
+        orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";
+        window.addEventListener(orientationEvent, front.doLayoutSize, false);
+        //$('#kiwi').bind("resize", front.doLayoutSize, false);
+
+        front.doLayout();
+        //front.windowAdd('server');
+        front.tabviewAdd('server');
+        
+        // Any pre-defined nick?
+        if (typeof init_data.nick === "string") {
             $('#kiwi .formconnectwindow .nick').val(init_data.nick);
         }
-               
-               //gateway.session_id = 'testses';
-               
-               $('#kiwi .cur_topic').keydown(function(e){
+        
+        //gateway.session_id = 'testses';
+        
+        $('#kiwi .cur_topic').keydown(function (e) {
             if (e.which === 13) {
                 // enter
                 e.preventDefault();
@@ -118,7 +124,7 @@ var front = {
                 $(this).text(front.original_topic);
                 $('#kiwi_msginput').focus();
             }
-               });
+        });
         /*$('.cur_topic').live('keypress', function(e) {
             if (e.keyCode === 13) {
                 // enter
@@ -131,7 +137,7 @@ var front = {
                 $(this).text(front.original_topic);
             }
         });*/
-        $('.cur_topic').live('change', function (e) {
+        $('.cur_topic').live('change', function () {
             var chan, text;
             text = $(this).text();
             if (text !== front.original_topic) {
@@ -141,293 +147,296 @@ var front = {
         });
         
         
-               gateway.start();
-               //front.sync();
-       },
-       
-       doLayoutSize: function () {
-           var kiwi = $('#kiwi');
-               if (kiwi.width() < 330 && !kiwi.hasClass('small_kiwi')) {
-                       console.log("switching to small kiwi");
-                       kiwi.removeClass('large_kiwi');
-                       kiwi.addClass('small_kiwi');
-               } else if (kiwi.width() >= 330 && !kiwi.hasClass('large_kiwi')) {
-                       kiwi.removeClass('small_kiwi');
-                       kiwi.addClass('large_kiwi');
-               }
-
-               var ct = $('#kiwi .cur_topic');
-               var ul = $('#kiwi .userlist');
-
-               var n_top = parseInt(ct.offset().top) + parseInt(ct.height());
-        n_top = n_top + parseInt(ct.css('border-top-width').replace('px', ''));
-        n_top = n_top + parseInt(ct.css('border-bottom-width').replace('px', ''));
-        n_top = n_top + parseInt(ct.css('padding-top').replace('px', ''));
-        n_top = n_top + parseInt(ct.css('padding-bottom').replace('px', ''));
-        n_top = n_top + 1; // Dunno why this is needed.. but it's always 1 px out :/
-
-        var n_bottom = $(document).height() - parseInt($('#kiwi .control').offset().top);
-
-               $('#kiwi .windows').css({top: n_top + 'px', bottom: n_bottom + 'px'});
-               $('#kiwi .userlist').css({top: n_top + 'px', bottom: n_bottom + 'px'});
-       },
-
-
-       doLayout: function () {
-               $('#kiwi .msginput .nick a').text(gateway.nick);
-               $('#kiwi_msginput').val(' ');
-               $('#kiwi_msginput').focus();
-       },
-       
-       
-       joinChannel: function (chan_name) {
-               var chans = chan_name.split(','),
+        gateway.start();
+        //front.sync();
+    },
+    
+    doLayoutSize: function () {
+        var kiwi, ct, ul, n_top, n_bottom;
+        kiwi = $('#kiwi');
+        if (kiwi.width() < 330 && !kiwi.hasClass('small_kiwi')) {
+            console.log("switching to small kiwi");
+            kiwi.removeClass('large_kiwi');
+            kiwi.addClass('small_kiwi');
+        } else if (kiwi.width() >= 330 && !kiwi.hasClass('large_kiwi')) {
+            kiwi.removeClass('small_kiwi');
+            kiwi.addClass('large_kiwi');
+        }
+
+        ct = $('#kiwi .cur_topic');
+        ul = $('#kiwi .userlist');
+
+        n_top = parseInt(ct.offset().top, 10) + parseInt(ct.height(), 10);
+        n_top = n_top + parseInt(ct.css('border-top-width').replace('px', ''), 10);
+        n_top = n_top + parseInt(ct.css('border-bottom-width').replace('px', ''), 10);
+        n_top = n_top + parseInt(ct.css('padding-top').replace('px', ''), 10);
+        n_top = n_top + parseInt(ct.css('padding-bottom').replace('px', ''), 10);
+        n_top += 1; // Dunno why this is needed.. but it's always 1 px out :/
+
+        n_bottom = $(document).height() - parseInt($('#kiwi .control').offset().top, 10);
+
+        $('#kiwi .windows').css({top: n_top + 'px', bottom: n_bottom + 'px'});
+        $('#kiwi .userlist').css({top: n_top + 'px', bottom: n_bottom + 'px'});
+    },
+
+
+    doLayout: function () {
+        $('#kiwi .msginput .nick a').text(gateway.nick);
+        $('#kiwi_msginput').val(' ');
+        $('#kiwi_msginput').focus();
+    },
+    
+    
+    joinChannel: function (chan_name) {
+        var chans = chan_name.split(','),
             i;
-               for (i in chans) {
-                       chan = chans[i];
-                       if (front.tabviews[chan.toLowerCase()] === undefined || (front.tabviews[chan.toLowerCase()] !== undefined && front.tabviews[chan.toLowerCase()].safe_to_close === true)) {
-                               gateway.join(chan);
-                               front.tabviewAdd(chan);
-                       } else {
-                               front.tabviews[chan.toLowerCase()].show();
-                       }
-               }
-       },
-       
-       
-       run: function (msg) {
-               console.log("running "+msg);
-               if (msg.substring(0, 1) === '/') {
-                       var parts = msg.split(' ');
-                       switch (parts[0].toLowerCase()) {
-                       case '/j':
-                       case '/join':
-                               front.joinChannel(parts[1]);
-                               break;
-                               
-                       case '/connect':
-                       case '/server':
-                               if (parts[1] === undefined) {
-                                       alert('Usage: /connect servername [port]');
-                                       break;
-                               }
-                               
-                               if (parts[2] === undefined) {
+        for (i in chans) {
+            chan = chans[i];
+            if (front.tabviews[chan.toLowerCase()] === undefined || (front.tabviews[chan.toLowerCase()] !== undefined && front.tabviews[chan.toLowerCase()].safe_to_close === true)) {
+                gateway.join(chan);
+                front.tabviewAdd(chan);
+            } else {
+                front.tabviews[chan.toLowerCase()].show();
+            }
+        }
+    },
+    
+    
+    run: function (msg) {
+        var parts, dest, t, pos, textRange, d;
+        console.log("running " + msg);
+        if (msg.substring(0, 1) === '/') {
+            parts = msg.split(' ');
+            switch (parts[0].toLowerCase()) {
+            case '/j':
+            case '/join':
+                front.joinChannel(parts[1]);
+                break;
+                
+            case '/connect':
+            case '/server':
+                if (parts[1] === undefined) {
+                    alert('Usage: /connect servername [port]');
+                    break;
+                }
+                
+                if (parts[2] === undefined) {
                     parts[2] = 6667;
                 }
-                               front.cur_channel.addMsg(null, ' ', '=== Connecting to ' + parts[1] + '...', 'status');
-                               gateway.connect(parts[1], parts[2], 0);
-                               break;
-                               
-                       case '/nick':
-                               console.log("/nick");
-                               if (parts[1] === undefined) {
-                                       console.log("calling show nick");
-                                       front.showChangeNick();
-                               } else {
-                                       console.log("sending raw");
-                                       gateway.raw(msg.substring(1));
-                               }
-                               break;
-
-                       case '/part':
-                               if (typeof parts[1] === "undefined") {
-                                       if(front.cur_channel.safe_to_close){
-                                               front.cur_channel.close();
-                                       } else {
-                                               gateway.raw(msg.substring(1) + ' ' + front.cur_channel.name);
-                                       }
-                               } else {
-                                       gateway.raw(msg.substring(1));
-                               }
-                               break;
-                               
-                       case '/names':
-                               if (typeof parts[1] !== "undefined") {
-                                       gateway.raw(msg.substring(1));
-                               }
-                               break;
-                               
-                       case '/debug':
-                               gateway.debug();
-                               break;
-                               
-                       case '/q':
-                       case '/query':
-                               if (typeof parts[1] !== "undefined") {
-                                       front.tabviewAdd(parts[1]);
-                               }
-                               break;
-                               
-                       case '/quote':
-                               gateway.raw(msg.replace(/^\/quote /i, ''));
-                               break;
-                               
-                       case '/me':
-                               gateway.action(front.cur_channel.name, msg.substring(4));
-                               //front.tabviews[destination.toLowerCase()].addMsg(null, ' ', '* '+data.nick+' '+data.msg, 'color:green;');
-                               front.cur_channel.addMsg(null, ' ', '* ' + gateway.nick + ' ' + msg.substring(4), 'action', 'color:#555;');
-                               break;
-
-                       case '/notice':
-                               var dest, msg;
-                               dest = parts[1];
-                               msg = parts.slice(2).join(' ');
-
-                               gateway.notice(dest, msg);
-                               this.onNotice({}, {nick:gateway.nick, channel:dest, msg:msg});
-                               break;
-
-                       case '/win':
-                               if (parts[1] !== undefined) {
-                                       front.windowsShow(parseInt(parts[1]));
-                               }
-                               break;
-
-                       case '/quit':
-                gateway.quit(msg.split(" ",2)[1]);
+                front.cur_channel.addMsg(null, ' ', '=== Connecting to ' + parts[1] + '...', 'status');
+                gateway.connect(parts[1], parts[2], 0);
+                break;
+                
+            case '/nick':
+                console.log("/nick");
+                if (parts[1] === undefined) {
+                    console.log("calling show nick");
+                    front.showChangeNick();
+                } else {
+                    console.log("sending raw");
+                    gateway.raw(msg.substring(1));
+                }
+                break;
+
+            case '/part':
+                if (typeof parts[1] === "undefined") {
+                    if (front.cur_channel.safe_to_close) {
+                        front.cur_channel.close();
+                    } else {
+                        gateway.raw(msg.substring(1) + ' ' + front.cur_channel.name);
+                    }
+                } else {
+                    gateway.raw(msg.substring(1));
+                }
+                break;
+                
+            case '/names':
+                if (typeof parts[1] !== "undefined") {
+                    gateway.raw(msg.substring(1));
+                }
+                break;
+                
+            case '/debug':
+                gateway.debug();
+                break;
+                
+            case '/q':
+            case '/query':
+                if (typeof parts[1] !== "undefined") {
+                    front.tabviewAdd(parts[1]);
+                }
+                break;
+                
+            case '/quote':
+                gateway.raw(msg.replace(/^\/quote /i, ''));
+                break;
+                
+            case '/me':
+                gateway.action(front.cur_channel.name, msg.substring(4));
+                //front.tabviews[destination.toLowerCase()].addMsg(null, ' ', '* '+data.nick+' '+data.msg, 'color:green;');
+                front.cur_channel.addMsg(null, ' ', '* ' + gateway.nick + ' ' + msg.substring(4), 'action', 'color:#555;');
+                break;
+
+            case '/notice':
+                dest = parts[1];
+                msg = parts.slice(2).join(' ');
+
+                gateway.notice(dest, msg);
+                this.onNotice({}, {nick: gateway.nick, channel: dest, msg: msg});
+                break;
+
+            case '/win':
+                if (parts[1] !== undefined) {
+                    front.windowsShow(parseInt(parts[1], 10));
+                }
+                break;
+
+            case '/quit':
+                gateway.quit(msg.split(" ", 2)[1]);
                 break;
 
             case '/topic':
-               if (parts[1] === undefined) {
-                       var t = $('.cur_topic');
-                                       if (t.createTextRange) {
-                                               var pos = t.text().length();
-                                           var textRange = t.createTextRange();
-                                           textRange.collapse(true);
-                                           textRange.moveEnd(pos);
-                                           textRange.moveStart(pos);
-                                           textRange.select();
-                                       } else if (t.setSelectionRange) {
-                                           t.setSelectionRange(pos,pos);
-                                       }
-               } else {
-                       gateway.setTopic(front.cur_channel.name, msg.split(' ', 2)[1]);
-                       //gateway.raw('TOPIC ' + front.cur_channel.name + ' :' + msg.split(' ', 2)[1]);
+                if (parts[1] === undefined) {
+                    t = $('.cur_topic');
+                    if (t.createTextRange) {
+                        pos = t.text().length();
+                        textRange = t.createTextRange();
+                        textRange.collapse(true);
+                        textRange.moveEnd(pos);
+                        textRange.moveStart(pos);
+                        textRange.select();
+                    } else if (t.setSelectionRange) {
+                        t.setSelectionRange(pos, pos);
+                    }
+                } else {
+                    gateway.setTopic(front.cur_channel.name, msg.split(' ', 2)[1]);
+                    //gateway.raw('TOPIC ' + front.cur_channel.name + ' :' + msg.split(' ', 2)[1]);
                 }
                 break;
-                       default:
-                               //front.cur_channel.addMsg(null, ' ', '--> Invalid command: '+parts[0].substring(1));
-                               gateway.raw(msg.substring(1));
-                       }
-
-               } else {
-                       //alert('Sending message: '+msg);
-                       if (msg.trim() === '') {
+            default:
+                //front.cur_channel.addMsg(null, ' ', '--> Invalid command: '+parts[0].substring(1));
+                gateway.raw(msg.substring(1));
+            }
+
+        } else {
+            //alert('Sending message: '+msg);
+            if (msg.trim() === '') {
                 return;
             }
             if (front.cur_channel.name !== 'server') {
-                               gateway.msg(front.cur_channel.name, msg);
-                               var d = new Date();
-                               d = d.getHours() + ":" + d.getMinutes();
-                               //front.addMsg(d, gateway.nick, msg);
-                               front.cur_channel.addMsg(null, gateway.nick, msg);
-                       }
-               }
-       },
-       
-       
-       onMsg: function (e, data) {
+                gateway.msg(front.cur_channel.name, msg);
+                d = new Date();
+                d = d.getHours() + ":" + d.getMinutes();
+                //front.addMsg(d, gateway.nick, msg);
+                front.cur_channel.addMsg(null, gateway.nick, msg);
+            }
+        }
+    },
+    
+    
+    onMsg: function (e, data) {
         var destination;
-               // Is this message from a user?
-               if (data.channel === gateway.nick) {
-                       destination = data.nick.toLowerCase();
-               } else {
-                       destination = data.channel.toLowerCase();       
-               }
-               
-               if (!front.tabviewExists(destination)) {
+        // Is this message from a user?
+        if (data.channel === gateway.nick) {
+            destination = data.nick.toLowerCase();
+        } else {
+            destination = data.channel.toLowerCase();    
+        }
+        
+        if (!front.tabviewExists(destination)) {
             front.tabviewAdd(destination);
         }
-               front.tabviews[destination].addMsg(null, data.nick, data.msg);
-       },
-       
-       onDebug: function (e, data) {
-               if (!front.tabviewExists('kiwi_debug')) {
+        front.tabviews[destination].addMsg(null, data.nick, data.msg);
+    },
+    
+    onDebug: function (e, data) {
+        if (!front.tabviewExists('kiwi_debug')) {
             front.tabviewAdd('kiwi_debug');
         }
-               front.tabviews.kiwi_debug.addMsg(null, ' ', data.msg);
-       },
-       
-       onAction: function (e, data) {
+        front.tabviews.kiwi_debug.addMsg(null, ' ', data.msg);
+    },
+    
+    onAction: function (e, data) {
         var destination;
-               // Is this message from a user?
-               if (data.channel === gateway.nick) {
-                       destination = data.nick;
-               } else {
-                       destination = data.channel;     
-               }
-               
-               if (!front.tabviewExists(destination)) {
+        // Is this message from a user?
+        if (data.channel === gateway.nick) {
+            destination = data.nick;
+        } else {
+            destination = data.channel;    
+        }
+        
+        if (!front.tabviewExists(destination)) {
             front.tabviewAdd(destination);
         }
-               front.tabviews[destination.toLowerCase()].addMsg(null, ' ', '* ' + data.nick + ' ' + data.msg, 'action', 'color:#555;');
-       },
-       
-       onTopic: function (e, data) {
-               if (front.tabviewExists(data.channel)) {
-                       front.tabviews[data.channel.toLowerCase()].changeTopic(data.topic);                     
-               }
-       },
-       
-       onNotice: function (e, data) {
-               var nick = (data.nick === undefined || data.nick === '') ? '' : '[' + data.nick + ']';
-               if (data.channel !== undefined) {
-                       if (front.tabviewExists(data.channel)) {
-                               front.tabviews[data.channel.toLowerCase()].addMsg(null, nick, data.msg, 'notice');
-                       } else {
-                               front.tabviews.server.addMsg(null, nick, data.msg, 'notice');
-                       }
-               } else {
-                       front.tabviews.server.addMsg(null, nick, data.msg, 'notice');
-               }
-       },
+        front.tabviews[destination.toLowerCase()].addMsg(null, ' ', '* ' + data.nick + ' ' + data.msg, 'action', 'color:#555;');
+    },
+    
+    onTopic: function (e, data) {
+        if (front.tabviewExists(data.channel)) {
+            front.tabviews[data.channel.toLowerCase()].changeTopic(data.topic);            
+        }
+    },
+    
+    onNotice: function (e, data) {
+        var nick = (data.nick === undefined || data.nick === '') ? '' : '[' + data.nick + ']';
+        if (data.channel !== undefined) {
+            if (front.tabviewExists(data.channel)) {
+                front.tabviews[data.channel.toLowerCase()].addMsg(null, nick, data.msg, 'notice');
+            } else {
+                front.tabviews.server.addMsg(null, nick, data.msg, 'notice');
+            }
+        } else {
+            front.tabviews.server.addMsg(null, nick, data.msg, 'notice');
+        }
+    },
     
     onCTCPRequest: function (e, data) {
         var msg = data.msg.split(" ", 2);
         switch (msg[0]) {
         case 'PING':
-               if(typeof msg[1] === 'undefined') msg[1] = '';
-            gateway.notice(data.nick, '\001PING ' + msg[1] + '\001');
+            if (typeof msg[1] === 'undefined') {
+                msg[1] = '';
+            }
+            gateway.notice(data.nick, String.fromCharCode(1) + 'PING ' + msg[1] + String.fromCharCode(1));
             break;
         case 'TIME':
-            gateway.notice(data.nick, '\001TIME ' + (new Date()).toLocaleString() + '\001');
+            gateway.notice(data.nick, String.fromCharCode(1) + 'TIME ' + (new Date()).toLocaleString() + String.fromCharCode(1));
             break;
         }
-        front.tabviews.server.addMsg(null, 'CTCP ['+data.nick+']', data.msg, 'ctcp');
+        front.tabviews.server.addMsg(null, 'CTCP [' + data.nick + ']', data.msg, 'ctcp');
     },
     
-    onCTCPResponse: function(e, data) {
+    onCTCPResponse: function (e, data) {
     },
     
-       onConnect: function (e, data) {
-               if (data.connected) {
-                       front.tabviews.server.addMsg(null, ' ', '=== Connected OK :)', 'status');
-                       if (typeof init_data.channel === "string") {
-                               front.joinChannel(init_data.channel);
-                       }
-               } else {
-                       front.tabviews.server.addMsg(null, ' ', '=== Failed to connect :(', 'status');
-               }
-       },
-       onDisconnect: function(e, data){
-               var tab;
-               for(tab in front.tabviews){
-                       front.tabviews[tab].addMsg(null, '', 'Disconnected from server!', 'error')
-               }
-       },
-       onOptions: function (e, data) {
-               if (typeof gateway.network_name === "string" && gateway.network_name !== "") {
-                       front.tabviews.server.tab.text(gateway.network_name);
-               }
-       },
-       onMOTD: function (e, data) {
-               front.tabviews.server.addMsg(null, data.server, data.msg, 'motd');
-       },
-       onWhois: function (e, data) {
+    onConnect: function (e, data) {
+        if (data.connected) {
+            front.tabviews.server.addMsg(null, ' ', '=== Connected OK :)', 'status');
+            if (typeof init_data.channel === "string") {
+                front.joinChannel(init_data.channel);
+            }
+        } else {
+            front.tabviews.server.addMsg(null, ' ', '=== Failed to connect :(', 'status');
+        }
+    },
+    onDisconnect: function (e, data) {
+        var tab;
+        for (tab in front.tabviews) {
+            front.tabviews[tab].addMsg(null, '', 'Disconnected from server!', 'error');
+        }
+    },
+    onOptions: function (e, data) {
+        if (typeof gateway.network_name === "string" && gateway.network_name !== "") {
+            front.tabviews.server.tab.text(gateway.network_name);
+        }
+    },
+    onMOTD: function (e, data) {
+        front.tabviews.server.addMsg(null, data.server, data.msg, 'motd');
+    },
+    onWhois: function (e, data) {
         var d;
         if (data.msg) {
-               front.cur_channel.addMsg(null, data.nick, data.msg, 'whois');
+            front.cur_channel.addMsg(null, data.nick, data.msg, 'whois');
         } else if (data.logon) {
             d = new Date();
             d.setTime(data.logon * 1000);
@@ -436,132 +445,141 @@ var front = {
         } else {
             front.cur_channel.addMsg(null, data.nick, 'idle for ' + data.idle + ' seconds', 'whois');
         }
-       },
-       onUserList: function (e, data) {
-               if (front.tabviews[data.channel.toLowerCase()] === undefined) {
+    },
+    onUserList: function (e, data) {
+        var ul, nick, mode;
+        if (front.tabviews[data.channel.toLowerCase()] === undefined) {
             return;
-               }
-               var ul = front.tabviews[data.channel.toLowerCase()].userlist;
-               
-               if (!document.userlist_updating) {
-                       document.userlist_updating = true;
-                       ul.empty();
-               }
-               
-               $.each(data.users, function (i, item) {
-                       var nick = i; //i.match(/^.+!/g);
-                       var mode = item;
-                       $('<li><a class="nick" onclick="front.userClick(this);">' + mode + nick + '</a></li>').appendTo(ul);
-               });
-               
-               front.tabviews[data.channel.toLowerCase()].userlistSort();
-       },
-       onUserListEnd: function (e, data) {
-               document.userlist_updating = false;
-       },
-       
-       onJoin: function (e, data) {
-               if (!front.tabviewExists(data.channel)) {
-                       front.tabviewAdd(data.channel.toLowerCase());
-               }
-               
-               if (data.nick === gateway.nick) {
+        }
+        ul = front.tabviews[data.channel.toLowerCase()].userlist;
+        
+        if (!document.userlist_updating) {
+            document.userlist_updating = true;
+            ul.empty();
+        }
+        
+        $.each(data.users, function (i, item) {
+            nick = i; //i.match(/^.+!/g);
+            mode = item;
+            $('<li><a class="nick" onclick="front.userClick(this);">' + mode + nick + '</a></li>').appendTo(ul);
+        });
+        
+        front.tabviews[data.channel.toLowerCase()].userlistSort();
+    },
+    onUserListEnd: function (e, data) {
+        document.userlist_updating = false;
+    },
+    
+    onJoin: function (e, data) {
+        if (!front.tabviewExists(data.channel)) {
+            front.tabviewAdd(data.channel.toLowerCase());
+        }
+        
+        if (data.nick === gateway.nick) {
             return; // Not needed as it's already in nicklist
         }
-               front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '--> ' + data.nick + ' has joined', 'action', 'color:#009900;');
-               $('<li><a class="nick" onclick="front.userClick(this);">' + data.nick + '</a></li>').appendTo(front.tabviews[data.channel.toLowerCase()].userlist);
-               front.tabviews[data.channel.toLowerCase()].userlistSort();
-       },
-       onPart: function (e, data) {
-               if (front.tabviewExists(data.channel)) {
-                       // If this is us, close the tabview
-                       if (data.nick === gateway.nick) {
-                               front.tabviews[data.channel.toLowerCase()].close();
-                               front.tabviews.server.show();
-                               return;
-                       }
-                       
-                       front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '<-- ' + data.nick + ' has left (' + data.message + ')', 'action', 'color:#990000;');
-                       front.tabviews[data.channel.toLowerCase()].userlist.children().each(function () {
-                               if ($(this).text() === data.nick) {
-                                       $(this).remove();
-                               }
-                       });
-               }
-       },
-       onKick: function (e, data) {
-               if (front.tabviewExists(data.channel)) {
-                       // If this is us, close the tabview
-                       if (data.kicked === gateway.nick) {
-                               //front.tabviews[data.channel.toLowerCase()].close();
-                               front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '=== You have been kicked from ' + data.channel + '. ' + data.message, 'status');
-                               front.tabviews[data.channel.toLowerCase()].safe_to_close = true;
-                               $('li', front.tabviews[data.channel.toLowerCase()].userlist).remove();
-                               return;
-                       }
-                       
-                       front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '<-- ' + data.kicked + ' kicked by ' + data.nick + '(' + data.message + ')', 'action', 'color:#990000;');
-                       front.tabviews[data.channel.toLowerCase()].userlist.children().each(function () {
-                               if ($(this).text() === data.nick) {
-                                       $(this).remove();
-                               }
-                       });
-               }
-       },
-       onNick: function (e, data) {
-               if (data.nick === gateway.nick) {
-                       gateway.nick = data.newnick;
-                       front.doLayout();
-               }
-               
-               $.each(front.tabviews, function (i, item) {
-                       $.each(front.tabviews, function (i, item) {
-                               item.changeNick(data.newnick, data.nick);
-                       });
-               });
-       },
-       onQuit: function (e, data) {
-               $.each(front.tabviews, function (i, item) {
-                       $.each(front.tabviews, function (i, item) {
-                               item.userlist.children().each(function () {
-                                       if ($(this).text() === data.nick) {
-                                               $(this).remove();
-                                               item.addMsg(null, ' ', '<-- ' + data.nick + ' has quit (' + data.message + ')', 'action', 'color:#990000;');
-                                       }
-                               });
-                       });
-               });
-       },
-       onChannelRedirect: function (e, data) {
-               front.tabviews[data.from.toLowerCase()].close();
-               front.tabviewAdd(data.to.toLowerCase());
-               front.tabviews[data.to.toLowerCase()].addMsg(null, ' ', '=== Redirected from ' + data.from, 'action');
-       },
-       
+        front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '--> ' + data.nick + ' has joined', 'action', 'color:#009900;');
+        $('<li><a class="nick" onclick="front.userClick(this);">' + data.nick + '</a></li>').appendTo(front.tabviews[data.channel.toLowerCase()].userlist);
+        front.tabviews[data.channel.toLowerCase()].userlistSort();
+    },
+    onPart: function (e, data) {
+        if (front.tabviewExists(data.channel)) {
+            // If this is us, close the tabview
+            if (data.nick === gateway.nick) {
+                front.tabviews[data.channel.toLowerCase()].close();
+                front.tabviews.server.show();
+                return;
+            }
+            
+            front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '<-- ' + data.nick + ' has left (' + data.message + ')', 'action', 'color:#990000;');
+            front.tabviews[data.channel.toLowerCase()].userlist.children().each(function () {
+                if ($(this).text() === data.nick) {
+                    $(this).remove();
+                }
+            });
+        }
+    },
+    onKick: function (e, data) {
+        if (front.tabviewExists(data.channel)) {
+            // If this is us, close the tabview
+            if (data.kicked === gateway.nick) {
+                //front.tabviews[data.channel.toLowerCase()].close();
+                front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '=== You have been kicked from ' + data.channel + '. ' + data.message, 'status');
+                front.tabviews[data.channel.toLowerCase()].safe_to_close = true;
+                $('li', front.tabviews[data.channel.toLowerCase()].userlist).remove();
+                return;
+            }
+            
+            front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '<-- ' + data.kicked + ' kicked by ' + data.nick + '(' + data.message + ')', 'action', 'color:#990000;');
+            front.tabviews[data.channel.toLowerCase()].userlist.children().each(function () {
+                if ($(this).text() === data.nick) {
+                    $(this).remove();
+                }
+            });
+        }
+    },
+    onNick: function (e, data) {
+        if (data.nick === gateway.nick) {
+            gateway.nick = data.newnick;
+            front.doLayout();
+        }
+        
+        $.each(front.tabviews, function (i, item) {
+            $.each(front.tabviews, function (i, item) {
+                item.changeNick(data.newnick, data.nick);
+            });
+        });
+    },
+    onQuit: function (e, data) {
+        $.each(front.tabviews, function (i, item) {
+            $.each(front.tabviews, function (i, item) {
+                item.userlist.children().each(function () {
+                    if ($(this).text() === data.nick) {
+                        $(this).remove();
+                        item.addMsg(null, ' ', '<-- ' + data.nick + ' has quit (' + data.message + ')', 'action', 'color:#990000;');
+                    }
+                });
+            });
+        });
+    },
+    onChannelRedirect: function (e, data) {
+        front.tabviews[data.from.toLowerCase()].close();
+        front.tabviewAdd(data.to.toLowerCase());
+        front.tabviews[data.to.toLowerCase()].addMsg(null, ' ', '=== Redirected from ' + data.from, 'action');
+    },
+    
     onIRCError: function (e, data) {
-       var t_view;
-       if (data.channel !== undefined && front.tabviewExists(data.channel)) {
-               t_view = data.channel;
-       } else {
-               t_view = 'server';
-       }
-
-        switch(data.error) {
+        var t_view;
+        if (data.channel !== undefined && front.tabviewExists(data.channel)) {
+            t_view = data.channel;
+        } else {
+            t_view = 'server';
+        }
+
+        switch (data.error) {
         case 'banned_from_channel':
             front.tabviews[t_view].addMsg(null, ' ', '=== You are banned from ' + data.channel + '. ' + data.reason, 'status');
-            if (t_view !== 'server' ) front.tabviews[t_view].safe_to_close = true;
+            if (t_view !== 'server') {
+                front.tabviews[t_view].safe_to_close = true;
+            }
             break;
         case 'bad_channel_key':
             front.tabviews[t_view].addMsg(null, ' ', '=== Bad channel key for ' + data.channel, 'status');
-            if (t_view !== 'server' ) front.tabviews[t_view].safe_to_close = true;
+            if (t_view !== 'server') {
+                front.tabviews[t_view].safe_to_close = true;
+            }
             break;
         case 'invite_only_channel':
             front.tabviews[t_view].addMsg(null, ' ', '=== ' + data.channel + ' is invite only.', 'status');
-            if (t_view !== 'server' ) front.tabviews[t_view].safe_to_close = true;
+            if (t_view !== 'server') {
+                front.tabviews[t_view].safe_to_close = true;
+            }
             break;
         case 'channel_is_full':
             front.tabviews[t_view].addMsg(null, ' ', '=== ' + data.channel + ' is full.', 'status');
-            if (t_view !== 'server' ) front.tabviews[t_view].safe_to_close = true;
+            if (t_view !== 'server') {
+                front.tabviews[t_view].safe_to_close = true;
+            }
             break;
         case 'chanop_privs_needed':
             front.tabviews[data.channel].addMsg(null, ' ', '=== ' + data.reason, 'status');
@@ -570,429 +588,440 @@ var front = {
             front.tabviews.server.addMsg(null, ' ', '=== ' + data.nick + ': ' + data.reason, 'status'); 
             break;
         default:
-               // We don't know what data contains, so don't do anything with it.
+            // We don't know what data contains, so don't do anything with it.
             //front.tabviews.server.addMsg(null, ' ', '=== ' + data, 'status');
         }
     },
     
-       registerKeys: function () {
-               $('#kiwi_msginput').bind('keydown', function (e) {
-                       var windows = $('#windows');
-                       //var meta = e.altKey;
-                       var meta = e.ctrlKey;
-                       
-                       switch (true) {
-                       case (e.which >= 48) && (e.which <= 57):
-                               if(meta){
-                                       var num = e.which - 48;
-                                       if(num === 0) num = 10;
-                                       num = num - 1;
-                                       front.windowsShow(num);
-                                       return false;
-                               }
-                               break;
-                       case e.which === 27:                    // escape                                       
-                               return false;
-                       case e.which === 13:                    // return
-                               var msg = $('#kiwi_msginput').val();
-                               msg = msg.trim();
-                               
-                               front.buffer.push(msg);
-                               front.buffer_pos = front.buffer.length;
-                               
-                               front.run(msg);
-                               $('#kiwi_msginput').val('');
-                               
-                               break;
-                       case e.which === 33:                    // page up
-                               console.log("page up");
-                               windows[0].scrollTop = windows[0].scrollTop - windows.height();
-                               return false;
-                               break;
-                       case e.which === 34:                    // page down
-                               windows[0].scrollTop = windows[0].scrollTop + windows.height();
-                               return false;
-                               break;
-                       case e.which === 37:                    // left
-                               if(meta){
-                                       front.windowsPrevious();
-                                       return false;
-                               }
-                               break;
-                       case e.which === 38:                    // up
-                               if (front.buffer_pos > 0) {
-                                       front.buffer_pos--;
-                                       $('#kiwi_msginput').val(front.buffer[front.buffer_pos]);
-                               }
-                               break;
-                       case e.which === 39:                    // right
-                               if(meta){
-                                       front.windowsNext();
-                                       return false;
-                               }
-                               break;
-                       case e.which === 40:                    // down
-                               if (front.buffer_pos < front.buffer.length) {
-                                       front.buffer_pos++;
-                                       $('#kiwi_msginput').val(front.buffer[front.buffer_pos]);
-                               }
-                               break;
-                               
-                       case e.which === 9:                             // tab
-                               // Get possible autocompletions
-                               var data = [];
-                               front.cur_channel.userlist.children().each(function () {
-                                       nick = front.nickStripPrefix($('a.nick', this).text());
-                                       data.push(nick);
-                               });
-                               
-                               // Do the autocomplete
-                               if (this.value.length === this.selectionStart && this.value.length === this.selectionEnd) {
-                                       var candidates = [];
-                                       
-                                       var word_pos = this.value.lastIndexOf(' ');
-                                       var word = "";
-                                       if (word_pos === -1) {
-                                               word = this.value;
-                                       } else {
-                                               word = this.value.substr(word_pos);
-                                       }
-                                       word = word.trim();
-                                       
-                                       // filter data to find only strings that start with existing value
-                                       for (i = 0; i < data.length; i++) {
-                                               if (data[i].indexOf(word) === 0 && data[i].length > word.length) {
-                                                       candidates.push(data[i]);
+    registerKeys: function () {
+        $('#kiwi_msginput').bind('keydown', function (e) {
+            var windows, meta, num, msg, data, candidates, word_pos, word;
+            windows = $('#windows');
+            //var meta = e.altKey;
+            meta = e.ctrlKey;
+            
+            switch (true) {
+            case (e.which >= 48) && (e.which <= 57):
+                if (meta) {
+                    num = e.which - 48;
+                    if (num === 0) {
+                        num = 10;
+                    }
+                    num = num - 1;
+                    front.windowsShow(num);
+                    return false;
+                }
+                break;
+            case e.which === 27:            // escape                    
+                return false;
+            case e.which === 13:            // return
+                msg = $('#kiwi_msginput').val();
+                msg = msg.trim();
+                
+                front.buffer.push(msg);
+                front.buffer_pos = front.buffer.length;
+                
+                front.run(msg);
+                $('#kiwi_msginput').val('');
+                
+                break;
+            case e.which === 33:             // page up
+                console.log("page up");
+                windows[0].scrollTop = windows[0].scrollTop - windows.height();
+                return false;
+            case e.which === 34:             // page down
+                windows[0].scrollTop = windows[0].scrollTop + windows.height();
+                return false;
+            case e.which === 37:            // left
+                if (meta) {
+                    front.windowsPrevious();
+                    return false;
+                }
+                break;
+            case e.which === 38:            // up
+                if (front.buffer_pos > 0) {
+                    front.buffer_pos--;
+                    $('#kiwi_msginput').val(front.buffer[front.buffer_pos]);
+                }
+                break;
+            case e.which === 39:            // right
+                if (meta) {
+                    front.windowsNext();
+                    return false;
+                }
+                break;
+            case e.which === 40:            // down
+                if (front.buffer_pos < front.buffer.length) {
+                    front.buffer_pos++;
+                    $('#kiwi_msginput').val(front.buffer[front.buffer_pos]);
+                }
+                break;
+                
+            case e.which === 9:                // tab
+                // Get possible autocompletions
+                data = [];
+                front.cur_channel.userlist.children().each(function () {
+                    nick = front.nickStripPrefix($('a.nick', this).text());
+                    data.push(nick);
+                });
+                
+                // Do the autocomplete
+                if (this.value.length === this.selectionStart && this.value.length === this.selectionEnd) {
+                    candidates = [];
+                    
+                    word_pos = this.value.lastIndexOf(' ');
+                    word = "";
+                    if (word_pos === -1) {
+                        word = this.value;
+                    } else {
+                        word = this.value.substr(word_pos);
+                    }
+                    word = word.trim();
+                    
+                    // filter data to find only strings that start with existing value
+                    for (i = 0; i < data.length; i++) {
+                        if (data[i].indexOf(word) === 0 && data[i].length > word.length) {
+                            candidates.push(data[i]);
                         }
-                                       }
-                                       
-                                       if (candidates.length > 0) {
-                                               // some candidates for autocompletion are found
-                                               this.value = this.value.substring(0, word_pos) + ' ' + candidates[0] + ': ';
-                                               this.selectionStart = this.value.length;
-                                       }
-                               }
-                               return false;
-                       }
-               });
-               
-               
-               $('#kiwi .control .msginput .nick').click(function () {
-                       front.showChangeNick();                 
-               });
-               
-               
-               
-               
-               
-               $('#kiwi .plugins .load_plugin_file').click(function () {
-                       if (typeof front.boxes.plugins !== "undefined") {
+                    }
+                    
+                    if (candidates.length > 0) {
+                        // some candidates for autocompletion are found
+                        this.value = this.value.substring(0, word_pos) + ' ' + candidates[0] + ': ';
+                        this.selectionStart = this.value.length;
+                    }
+                }
+                return false;
+            }
+        });
+        
+        
+        $('#kiwi .control .msginput .nick').click(function () {
+            front.showChangeNick();            
+        });
+        
+        
+        
+        
+        
+        $('#kiwi .plugins .load_plugin_file').click(function () {
+            var lst, j, txt;
+            if (typeof front.boxes.plugins !== "undefined") {
                 return;
             }
-                       
-                       front.boxes.plugins = new box("plugin_file");
-                       $('#tmpl_plugins').tmpl({}).appendTo(front.boxes.plugins.content);
-                       front.boxes.plugins.box.css('top', -(front.boxes.plugins.height + 40));
-                       
-                       // Populate the plugin list..
-                       var lst = $('#plugin_list');
-                       lst.find('option').remove();
-            var j;
-                       for (j in plugins.privmsg) {
-                               var txt = plugins.privmsg[j].name;
-                               lst.append('<option value="' + txt + '">' + txt + '</option>');
-                       }
-                       
-                       // Event bindings
-                       $('#kiwi .plugin_file').submit(function () {
-                               $.getJSON($('.txtpluginfile').val(), function (data) {
-                                       var plg = {};
-                                       plg.name = data.name;
-                                       eval("plg.onprivmsg = " + data.onprivmsg);
-                                       eval("plg.onload = " + data.onload);
-                                       eval("plg.onunload = " + data.onunload);
-                                       plugins.privmsg.push(plg);
-                                       
-                                       if (plg.onload instanceof Function) {
+            
+            front.boxes.plugins = new Box("plugin_file");
+            $('#tmpl_plugins').tmpl({}).appendTo(front.boxes.plugins.content);
+            front.boxes.plugins.box.css('top', -(front.boxes.plugins.height + 40));
+            
+            // Populate the plugin list..
+            lst = $('#plugin_list');
+            lst.find('option').remove();
+            for (j in plugins.privmsg) {
+                txt = plugins.privmsg[j].name;
+                lst.append('<option value="' + txt + '">' + txt + '</option>');
+            }
+            
+            // Event bindings
+            $('#kiwi .plugin_file').submit(function () {
+                $.getJSON($('.txtpluginfile').val(), function (data) {
+                    var plg = {};
+                    plg.name = data.name;
+                    eval("plg.onprivmsg = " + data.onprivmsg);
+                    eval("plg.onload = " + data.onload);
+                    eval("plg.onunload = " + data.onunload);
+                    plugins.privmsg.push(plg);
+                    
+                    if (plg.onload instanceof Function) {
                         plg.onload();
                     }
-                               });
-                               return false;
-                       });
-                       $('#kiwi .cancelpluginfile').click(function () {
-                               front.boxes.plugins.destroy();
-                       });
-                       
-                       $('#kiwi #plugins_list_unload').click(function () {
-                               var selected_plugin = $('#plugin_list').val();
-                               console.log("removing plugin: "+selected_plugin);
-                               for (var i in plugins.privmsg) {
-                                       if (plugins.privmsg[i].name === selected_plugin) {
-                                               if (plugins.privmsg[i].onunload instanceof Function)
-                                                       plugins.privmsg[i].onunload();
-                                               
-                                               delete plugins.privmsg[i];
-                                       }
-                               }
-                       });
-                       
-                       $('#kiwi .txtpluginfile').focus();
-                       
-               });
-               
-               $('#kiwi .plugins .reload_css').click(function () {
-                       var links = document.getElementsByTagName("link");
-                       for (var i=0; i < links.length; i++) {
-                               if (links[i].rel === "stylesheet") {
-                                       if (links[i].href.indexOf("?")===-1) {
-                                               links[i].href += "?";
-                                       }
-                                       links[i].href += "x";
-                               }
-                       }
-               });
-
-
-               $('#kiwi .about .about_close').click(function () {
-                       $('#kiwi .about').css('display', 'none');
-               });
-               
-               
-               $('#kiwi .poweredby').click(function () {
-                       $('#kiwi .about').css('display', 'block');
-               });
-               
-       },
-       
-       
-       showChangeNick: function(){
-               $('#kiwi').append($('#tmpl_change_nick').tmpl({}));
-               
-               $('#kiwi .form_newnick').submit(function () {
-                       front.run('/NICK ' + $('#kiwi .txtnewnick').val());
-                       $('#kiwi .newnick').remove();
-                       return false;
-               });
-               
-               $('#kiwi .txtnewnick').keypress(function(ev){
-                       if(!this.first_press) {
-                               this.first_press=true;
-                               return false;
-                       }
-               });
-
-               $('#kiwi .txtnewnick').keydown(function(ev){
-                       if(ev.which === 27){  // ESC
-                               $('#kiwi_msginput').focus();
-                               $('#kiwi .newnick').remove();
-                       }
-               });
-               
-               $('#kiwi .cancelnewnick').click(function () {
-                       $('#kiwi .newnick').remove();
-               });
-               
-               $('#kiwi .txtnewnick').focus();
-       },
-
-
-       tabviewExists: function (name) {
-               return !(front.tabviews[name.toLowerCase()] == undefined);
-       },
-       
-       tabviewAdd: function (v_name) {
-               if (v_name.charAt(0) == gateway.channel_prefix) {
-                       var re = new RegExp(gateway.channel_prefix,"g");
-                       var htmlsafe_name = v_name.replace(re, 'pre');
-                       htmlsafe_name = "chan_" + htmlsafe_name;
-               } else {
-                       var htmlsafe_name = 'query_' + v_name;
-               }
-               
-               var tmp_divname = 'kiwi_window_' + htmlsafe_name;
-               var tmp_userlistname = 'kiwi_userlist_' + htmlsafe_name;
-               var tmp_tabname = 'kiwi_tab_' + htmlsafe_name
-               
-               if(!front.tabviewExists(v_name)){
-                       $('#kiwi .windows .scroller').append('<div id="' + tmp_divname + '" class="messages"></div>');
-                       $('#kiwi .userlist').append('<ul id="' + tmp_userlistname + '"></ul>');
-                       $('#kiwi .windowlist ul').append('<li id="' + tmp_tabname + '" onclick="front.tabviews[\'' + v_name.toLowerCase() + '\'].show();">' + v_name + '</li>');
-               }
-               //$('#kiwi .windowlist ul .window_'+v_name).click(function(){ front.windowShow(v_name); });
-               //front.windowShow(v_name);
-               
-               front.tabviews[v_name.toLowerCase()] = new tabview();
-               front.tabviews[v_name.toLowerCase()].name = v_name;
-               front.tabviews[v_name.toLowerCase()].div = $('#'+tmp_divname);
-               front.tabviews[v_name.toLowerCase()].userlist = $('#'+tmp_userlistname);
-               front.tabviews[v_name.toLowerCase()].tab = $('#'+tmp_tabname);
-               front.tabviews[v_name.toLowerCase()].show();
-               
-               if (typeof registerTouches === "function") {
-                       //alert("Registering touch interface");
-                       //registerTouches($('#'+tmp_divname));
-                       registerTouches(document.getElementById(tmp_divname));
-               }
-               /*
-               front.tabviews[v_name.toLowerCase()].userlist.click(function(){
-                       alert($(this).attr('id'));
-               });
-               */
-
-               front.doLayoutSize();
-       },
-       
-       
-       userClick: function (item) {
-               // Remove any existing userboxes
-               $('#kiwi .userbox').remove();
-               
-               var li = $(item).parent();
-               /*var html = '<div class="userbox">\
-       <input type="hidden" class="userbox_nick" value="' + front.nickStripPrefix($(item).text()) + '" />\
-       <a href="#" class="userbox_query">Message</a>\
-       <a href="#" class="userbox_whois">Info</a>\
+                });
+                return false;
+            });
+            $('#kiwi .cancelpluginfile').click(function () {
+                front.boxes.plugins.destroy();
+            });
+            
+            $('#kiwi #plugins_list_unload').click(function () {
+                var selected_plugin, i;
+                selected_plugin = $('#plugin_list').val();
+                console.log("removing plugin: " + selected_plugin);
+                for (i in plugins.privmsg) {
+                    if (plugins.privmsg[i].name === selected_plugin) {
+                        if (plugins.privmsg[i].onunload instanceof Function) {
+                            plugins.privmsg[i].onunload();
+                        }
+                        delete plugins.privmsg[i];
+                    }
+                }
+            });
+            
+            $('#kiwi .txtpluginfile').focus();
+            
+        });
+        
+        $('#kiwi .plugins .reload_css').click(function () {
+            var links = document.getElementsByTagName("link"),
+                i;
+            for (i = 0; i < links.length; i++) {
+                if (links[i].rel === "stylesheet") {
+                    if (links[i].href.indexOf("?") === -1) {
+                        links[i].href += "?";
+                    }
+                    links[i].href += "x";
+                }
+            }
+        });
+
+
+        $('#kiwi .about .about_close').click(function () {
+            $('#kiwi .about').css('display', 'none');
+        });
+        
+        
+        $('#kiwi .poweredby').click(function () {
+            $('#kiwi .about').css('display', 'block');
+        });
+        
+    },
+    
+    
+    showChangeNick: function () {
+        $('#kiwi').append($('#tmpl_change_nick').tmpl({}));
+        
+        $('#kiwi .form_newnick').submit(function () {
+            front.run('/NICK ' + $('#kiwi .txtnewnick').val());
+            $('#kiwi .newnick').remove();
+            return false;
+        });
+        
+        $('#kiwi .txtnewnick').keypress(function (ev) {
+            if (!this.first_press) {
+                this.first_press = true;
+                return false;
+            }
+        });
+
+        $('#kiwi .txtnewnick').keydown(function (ev) {
+            if (ev.which === 27) {  // ESC
+                $('#kiwi_msginput').focus();
+                $('#kiwi .newnick').remove();
+            }
+        });
+        
+        $('#kiwi .cancelnewnick').click(function () {
+            $('#kiwi .newnick').remove();
+        });
+        
+        $('#kiwi .txtnewnick').focus();
+    },
+
+
+    tabviewExists: function (name) {
+        return (typeof front.tabviews[name.toLowerCase()] !== 'undefined');
+    },
+    
+    tabviewAdd: function (v_name) {
+        var re, htmlsafe_name, tmp_divname, tmp_userlistname, tmp_tabname;
+        if (v_name.charAt(0) === gateway.channel_prefix) {
+            re = new RegExp(gateway.channel_prefix, "g");
+            htmlsafe_name = v_name.replace(re, 'pre');
+            htmlsafe_name = "chan_" + htmlsafe_name;
+        } else {
+            htmlsafe_name = 'query_' + v_name;
+        }
+        
+        tmp_divname = 'kiwi_window_' + htmlsafe_name;
+        tmp_userlistname = 'kiwi_userlist_' + htmlsafe_name;
+        tmp_tabname = 'kiwi_tab_' + htmlsafe_name;
+        
+        if (!front.tabviewExists(v_name)) {
+            $('#kiwi .windows .scroller').append('<div id="' + tmp_divname + '" class="messages"></div>');
+            $('#kiwi .userlist').append('<ul id="' + tmp_userlistname + '"></ul>');
+            $('#kiwi .windowlist ul').append('<li id="' + tmp_tabname + '" onclick="front.tabviews[\'' + v_name.toLowerCase() + '\'].show();">' + v_name + '</li>');
+        }
+        //$('#kiwi .windowlist ul .window_'+v_name).click(function(){ front.windowShow(v_name); });
+        //front.windowShow(v_name);
+        
+        front.tabviews[v_name.toLowerCase()] = new Tabview();
+        front.tabviews[v_name.toLowerCase()].name = v_name;
+        front.tabviews[v_name.toLowerCase()].div = $('#' + tmp_divname);
+        front.tabviews[v_name.toLowerCase()].userlist = $('#' + tmp_userlistname);
+        front.tabviews[v_name.toLowerCase()].tab = $('#' + tmp_tabname);
+        front.tabviews[v_name.toLowerCase()].show();
+        
+        if (typeof registerTouches === "function") {
+            //alert("Registering touch interface");
+            //registerTouches($('#'+tmp_divname));
+            registerTouches(document.getElementById(tmp_divname));
+        }
+        /*
+        front.tabviews[v_name.toLowerCase()].userlist.click(function(){
+            alert($(this).attr('id'));
+        });
+        */
+
+        front.doLayoutSize();
+    },
+    
+    
+    userClick: function (item) {
+        // Remove any existing userboxes
+        $('#kiwi .userbox').remove();
+        
+        var li = $(item).parent();
+        /*var html = '<div class="userbox">\
+    <input type="hidden" class="userbox_nick" value="' + front.nickStripPrefix($(item).text()) + '" />\
+    <a href="#" class="userbox_query">Message</a>\
+    <a href="#" class="userbox_whois">Info</a>\
 </div>';
-               li.append(html);*/
-               $('#tmpl_user_box').tmpl({nick: front.nickStripPrefix($(item).text())}).appendTo(li);
-               
-               $('#kiwi .userbox .userbox_query').click(function (ev) {
-                       var nick = $('#kiwi .userbox_nick').val();
-                       front.run('/query ' + nick);
-               });
-               
-               $('#kiwi .userbox .userbox_whois').click(function (ev) {
-                       var nick = $('#kiwi .userbox_nick').val();
-                       front.run('/whois ' + nick);
-               });
-       },
-       
-       
-       sync: function () {
-               gateway.sync();
-       },
-       
-       onSync: function (e, data) {
-               // Set any settings
-               if (data.nick != undefined) gateway.nick = data.nick;
-               
-               // Add the tabviews
-               if (data.tabviews != undefined) {
-                       $.each(data.tabviews, function (i, tab) {
-                               if(!front.tabviewExists(tab.name)){
-                                       front.tabviewAdd(gateway.channel_prefix + tab.name);
-                                       
-                                       if (tab.userlist !== undefined)
-                                               front.onUserList({'channel':gateway.channel_prefix + tab.name, 'users':tab.userlist});
-                               }
-                       });
-               }
-               
-               front.doLayout();
-       },
-       
-       
-       setTopicText: function (new_topic) {
+        li.append(html);*/
+        $('#tmpl_user_box').tmpl({nick: front.nickStripPrefix($(item).text())}).appendTo(li);
+        
+        $('#kiwi .userbox .userbox_query').click(function (ev) {
+            var nick = $('#kiwi .userbox_nick').val();
+            front.run('/query ' + nick);
+        });
+        
+        $('#kiwi .userbox .userbox_whois').click(function (ev) {
+            var nick = $('#kiwi .userbox_nick').val();
+            front.run('/whois ' + nick);
+        });
+    },
+    
+    
+    sync: function () {
+        gateway.sync();
+    },
+    
+    onSync: function (e, data) {
+        // Set any settings
+        if (data.nick !== undefined) {
+            gateway.nick = data.nick;
+        }
+        
+        // Add the tabviews
+        if (data.tabviews !== undefined) {
+            $.each(data.tabviews, function (i, tab) {
+                if (!front.tabviewExists(tab.name)) {
+                    front.tabviewAdd(gateway.channel_prefix + tab.name);
+                    
+                    if (tab.userlist !== undefined) {
+                        front.onUserList({'channel': gateway.channel_prefix + tab.name, 'users': tab.userlist});
+                    }
+                }
+            });
+        }
+        
+        front.doLayout();
+    },
+    
+    
+    setTopicText: function (new_topic) {
         front.original_topic = new_topic;
-               $('#kiwi .cur_topic .topic').text(new_topic);
-               front.doLayoutSize();
-       },
-       
-       
-       
-       
-       
-       
-       
-       nickStripPrefix: function (nick) {
-               var tmp = nick;
-               
-               prefix = tmp.charAt(0);
-               for(var i in gateway.user_prefixes){
-                       if(gateway.user_prefixes[i].symbol !== prefix) continue;
-                       return tmp.substring(1);
-               }
-
-               return tmp;
-       },
-       
-       nickGetPrefix: function (nick) {
-               var tmp = nick;
-               
-               prefix = tmp.charAt(0);
-               for(var i in gateway.user_prefixes){
-                       if(gateway.user_prefixes[i].symbol === prefix){
-                               return prefix;
-                       }
-               }
-
-               return '';
-       },
-       
-       isChannel: function (name) {
-               prefix = name.charAt(0);
-               if (gateway.channel_prefix.indexOf(prefix) > -1) {
-                       is_chan = true;
-               } else {
-                       is_chan = false;
-               }
-               
-               return is_chan;
-       },
-       
-       tabviewsNext: function(){
-               var wl = $('#kiwi .windowlist ul');
-               var next_left = parseInt(wl.css('text-indent').replace('px', ''))+170;
-               wl.css('text-indent', next_left);
-       },
-       
-       tabviewsPrevious: function(){
-               var wl = $('#kiwi .windowlist ul');
-               var next_left = parseInt(wl.css('text-indent').replace('px', ''))-170;
-               wl.css('text-indent', next_left);
-       },
-
-       windowsNext: function(){
-               var tab, next;
-               next = false;
-               for(tab in front.tabviews){
-                       if(!next){
-                               if(front.tabviews[tab] == front.cur_channel){
-                                       next = true;
-                                       continue;
-                               }
-                       } else {
-                               front.tabviews[tab].show();
-                               return;
-                       }
-               };
-       },
-
-       windowsPrevious: function(){
-               var tab, prev_tab, next;
-               next = false;
-               for(tab in front.tabviews){
-                       if(front.tabviews[tab] == front.cur_channel){
-                               if(prev_tab) prev_tab.show();
-                               return;
-                       }
-                       prev_tab = front.tabviews[tab];
-               };
-       },
-
-       windowsShow: function(num){
-               num = parseInt(num);
-               console.log('Showing window '+num.toString());
-               var i = 0, tab;
-               for(tab in front.tabviews){
-                       if(i === num){
-                               front.tabviews[tab].show();
-                               return;
-                       }
-                       i++;
-               }
-       }
-}
+        $('#kiwi .cur_topic .topic').text(new_topic);
+        front.doLayoutSize();
+    },
+    
+    
+    
+    
+    
+    
+    
+    nickStripPrefix: function (nick) {
+        var tmp = nick, i;
+        
+        prefix = tmp.charAt(0);
+        for (i in gateway.user_prefixes) {
+            if (gateway.user_prefixes[i].symbol !== prefix) {
+                continue;
+            }
+            return tmp.substring(1);
+        }
+
+        return tmp;
+    },
+    
+    nickGetPrefix: function (nick) {
+        var tmp = nick, i;
+        
+        prefix = tmp.charAt(0);
+        for (i in gateway.user_prefixes) {
+            if (gateway.user_prefixes[i].symbol === prefix) {
+                return prefix;
+            }
+        }
+
+        return '';
+    },
+    
+    isChannel: function (name) {
+        prefix = name.charAt(0);
+        if (gateway.channel_prefix.indexOf(prefix) > -1) {
+            is_chan = true;
+        } else {
+            is_chan = false;
+        }
+        
+        return is_chan;
+    },
+    
+    tabviewsNext: function () {
+        var wl = $('#kiwi .windowlist ul'),
+            next_left = parseInt(wl.css('text-indent').replace('px', ''), 10) + 170;
+        wl.css('text-indent', next_left);
+    },
+    
+    tabviewsPrevious: function () {
+        var wl = $('#kiwi .windowlist ul'),
+            next_left = parseInt(wl.css('text-indent').replace('px', ''), 10) - 170;
+        wl.css('text-indent', next_left);
+    },
+
+    windowsNext: function () {
+        var tab, next;
+        next = false;
+        for (tab in front.tabviews) {
+            if (!next) {
+                if (front.tabviews[tab] === front.cur_channel) {
+                    next = true;
+                    continue;
+                }
+            } else {
+                front.tabviews[tab].show();
+                return;
+            }
+        }
+    },
+
+    windowsPrevious: function () {
+        var tab, prev_tab, next;
+        next = false;
+        for (tab in front.tabviews) {
+            if (front.tabviews[tab] === front.cur_channel) {
+                if (prev_tab) {
+                    prev_tab.show();
+                }
+                return;
+            }
+            prev_tab = front.tabviews[tab];
+        }
+    },
+
+    windowsShow: function (num) {
+        num = parseInt(num, 10);
+        console.log('Showing window ' + num.toString());
+        var i = 0, tab;
+        for (tab in front.tabviews) {
+            if (i === num) {
+                front.tabviews[tab].show();
+                return;
+            }
+            i++;
+        }
+    }
+};
 
 
 
@@ -1017,247 +1046,278 @@ var front = {
  */
 
 
-var tabview = function(){}
-tabview.prototype.name = null;
-tabview.prototype.div = null;
-tabview.prototype.userlist = null;
-tabview.prototype.tab = null;
-tabview.prototype.topic = "";
-tabview.prototype.safe_to_close = false;                               // If we have been kicked/banned/etc from this channel, don't wait for a part message
-
-tabview.prototype.show = function(){
-       $('#kiwi .messages').removeClass("active");
-       $('#kiwi .userlist ul').removeClass("active");
-       $('#kiwi .windowlist ul li').removeClass("active");
-       
-       // Activate this tab!
-       this.div.addClass('active');
-       this.userlist.addClass('active');
-       this.tab.addClass('active');
-       
-       document.tmp = this.div;
-       // Add the part image to the tab
-       this.addPartImage();
-       
-       this.clearHighlight();
-       front.setTopicText(this.topic);
-       front.cur_channel = this;
-       
-       // If we're using fancy scrolling, refresh it
-       if(touch_scroll) touch_scroll.refresh();
-
-       this.scrollBottom();
-       if(!touchscreen) $('#kiwi_msginput').focus();
-}
-
-tabview.prototype.close = function(){
-       this.div.remove();
-       this.userlist.remove();
-       this.tab.remove();
-       
-       if(front.cur_channel == this) front.tabviews['server'].show();
-       delete front.tabviews[this.name.toLowerCase()];
-}
-
-tabview.prototype.addPartImage = function(){
-       this.clearPartImage();
-       
-       // We can't close this tab, so don't have the close image
-       if(this.name == 'server') return;
-
-       var del_html = '<img src="img/redcross.png" class="tab_part" />';
-       this.tab.append(del_html);
-       
-       $('.tab_part', this.tab).click(function(){
-               if(front.isChannel($(this).parent().text())){
-                       front.run("/part");
-               } else {
-                       // Make sure we don't close the server tab
-                       if(front.cur_channel.name != 'server') front.cur_channel.close();
-               }
-       });
-}
-
-tabview.prototype.clearPartImage = function(){
-       $('#kiwi .windowlist .tab_part').remove();
-}
-
-tabview.prototype.addMsg = function(time, nick, msg, type, style){
-       //if(nick.charAt(0) != "[" && nick != ""){
-       //      var html_nick = $('<div/>').text('<'+nick+'>').html();
-       //} else {
-               var html_nick = $('<div/>').text(nick).html();
-       //}
-       
-       var self = this;
-       
-       var tmp = msg;
-       var plugin_ret = '';
-       for(var i in plugins.privmsg){
-               if ((plugins.privmsg[i].onprivmsg instanceof Function)) {
-                       plugin_ret = '';
-                       try {
-                               plugin_ret = plugins.privmsg[i].onprivmsg(tmp, this.name);
-                               
-                               // If this plugin has returned false, do not add this message
-                               if(plugin_ret === false) return;
-                       } catch (e){}
-                       
-                       // If we actually have a string from the plugin, use it
-                       if(typeof plugin_ret == "string") tmp = plugin_ret;
-               }
-       }
-       msg = tmp;
-       
-       //var html_msg = $('<div/>').text(msg).html()+' '; // Add the space so the styling always has at least 1 character to go from
-       if(time == null){
-               var d = new Date();
-               time = d.getHours().toString().lpad(2, "0") + ":" + d.getMinutes().toString().lpad(2, "0") + ":" + d.getSeconds().toString().lpad(2, "0");
-       }
-       
-       // The CSS class (action, topic, notice, etc)
-       if(typeof type != "string") type = '';
-       
-       // Make sure we don't have NaN or something
-       if(typeof msg != "string") msg = '';
-       
-       // Text formatting
-       // bold
-       if(msg.indexOf(String.fromCharCode(2))){
-               next = '<b>';
-               while(msg.indexOf(String.fromCharCode(2)) != -1){
-                       msg = msg.replace(String.fromCharCode(2), next);
-                       next = (next=='<b>') ? '</b>' : '<b>';
-               }
-               if(next == '</b>') msg =+ '</b>';
-       }
-       
-       // Wierd thing noticed by Dux0r on the irc.esper.net server
-       if(typeof msg != "string") msg = '';
-       
-       // underline
-       if(msg.indexOf(String.fromCharCode(31))){
-               next = '<u>';
-               while(msg.indexOf(String.fromCharCode(31)) != -1){
-                       msg = msg.replace(String.fromCharCode(31), next);
-                       next = (next=='<u>') ? '</u>' : '<u>';
-               }
-               if(next == '</u>') msg =+ '</u>';
-       }
-       
-    var re = '\\B(' + gateway.channel_prefix + '[^ ,.\\007]+)';
-    re = new RegExp(re, 'g');
-       
-    msg = msg.replace(re, function(match) {
+var Tabview = function () {};
+Tabview.prototype.name = null;
+Tabview.prototype.div = null;
+Tabview.prototype.userlist = null;
+Tabview.prototype.tab = null;
+Tabview.prototype.topic = "";
+Tabview.prototype.safe_to_close = false;                // If we have been kicked/banned/etc from this channel, don't wait for a part message
+
+Tabview.prototype.show = function () {
+    $('#kiwi .messages').removeClass("active");
+    $('#kiwi .userlist ul').removeClass("active");
+    $('#kiwi .windowlist ul li').removeClass("active");
+    
+    // Activate this tab!
+    this.div.addClass('active');
+    this.userlist.addClass('active');
+    this.tab.addClass('active');
+    
+    document.tmp = this.div;
+    // Add the part image to the tab
+    this.addPartImage();
+    
+    this.clearHighlight();
+    front.setTopicText(this.topic);
+    front.cur_channel = this;
+    
+    // If we're using fancy scrolling, refresh it
+    if (touch_scroll) {
+        touch_scroll.refresh();
+    }
+
+    this.scrollBottom();
+    if (!touchscreen) {
+        $('#kiwi_msginput').focus();
+    }
+};
+
+Tabview.prototype.close = function () {
+    this.div.remove();
+    this.userlist.remove();
+    this.tab.remove();
+    
+    if (front.cur_channel === this) {
+        front.tabviews.server.show();
+    }
+    delete front.tabviews[this.name.toLowerCase()];
+};
+
+Tabview.prototype.addPartImage = function () {
+    this.clearPartImage();
+    
+    // We can't close this tab, so don't have the close image
+    if (this.name === 'server') {
+        return;
+    }
+
+    var del_html = '<img src="img/redcross.png" class="tab_part" />';
+    this.tab.append(del_html);
+    
+    $('.tab_part', this.tab).click(function () {
+        if (front.isChannel($(this).parent().text())) {
+            front.run("/part");
+        } else {
+            // Make sure we don't close the server tab
+            if (front.cur_channel.name !== 'server') {
+                front.cur_channel.close();
+            }
+        }
+    });
+};
+
+Tabview.prototype.clearPartImage = function () {
+    $('#kiwi .windowlist .tab_part').remove();
+};
+
+Tabview.prototype.addMsg = function (time, nick, msg, type, style) {
+    var html_nick, self, tmp, plugin_ret, i, d, re, line_msg;
+    html_nick = $('<div/>').text(nick).html();
+    
+    self = this;
+    
+    tmp = msg;
+    plugin_ret = '';
+    for (i in plugins.privmsg) {
+        if ((plugins.privmsg[i].onprivmsg instanceof Function)) {
+            plugin_ret = '';
+            try {
+                plugin_ret = plugins.privmsg[i].onprivmsg(tmp, this.name);
+                
+                // If this plugin has returned false, do not add this message
+                if (plugin_ret === false) {
+                    return;
+                }
+            } catch (e) {
+            }
+            
+            // If we actually have a string from the plugin, use it
+            if (typeof plugin_ret === "string") {
+                tmp = plugin_ret;
+            }
+        }
+    }
+    msg = tmp;
+    
+    //var html_msg = $('<div/>').text(msg).html()+' '; // Add the space so the styling always has at least 1 character to go from
+    if (time === null) {
+        d = new Date();
+        time = d.getHours().toString().lpad(2, "0") + ":" + d.getMinutes().toString().lpad(2, "0") + ":" + d.getSeconds().toString().lpad(2, "0");
+    }
+    
+    // The CSS class (action, topic, notice, etc)
+    if (typeof type !== "string") {
+        type = '';
+    }
+    
+    // Make sure we don't have NaN or something
+    if (typeof msg !== "string") {
+        msg = '';
+    }
+    
+    // Text formatting
+    // bold
+    if (msg.indexOf(String.fromCharCode(2)) !== -1) {
+        next = '<b>';
+        while (msg.indexOf(String.fromCharCode(2)) !== -1) {
+            msg = msg.replace(String.fromCharCode(2), next);
+            next = (next === '<b>') ? '</b>' : '<b>';
+        }
+        if (next === '</b>') {
+            msg = msg + '</b>';
+        }
+    }
+    
+    // Wierd thing noticed by Dux0r on the irc.esper.net server
+    if (typeof msg !== "string") {
+        msg = '';
+    }
+    
+    // underline
+    if (msg.indexOf(String.fromCharCode(31)) !== -1) {
+        next = '<u>';
+        while (msg.indexOf(String.fromCharCode(31)) !== -1) {
+            msg = msg.replace(String.fromCharCode(31), next);
+            next = (next === '<u>') ? '</u>' : '<u>';
+        }
+        if (next === '</u>') {
+            msg = msg + '</u>';
+        }
+    }
+    
+    re = new RegExp('\\B(' + gateway.channel_prefix + '[^ ,.\\007]+)', 'g');
+    
+    msg = msg.replace(re, function (match) {
         return '<a class="chan" href="#">' + match + '</a>';
     });
 
-       var line_msg = $('<div class="msg '+type+'"><div class="time">'+time+'</div><div class="nick">'+html_nick+'</div><div class="text" style="'+style+'">'+msg+' </div></div>');
-       this.div.append(line_msg);
-
-       if(!touchscreen){
-               this.scrollBottom();
-       } else {
-               touch_scroll.refresh();
-               //console.log(this.div.attr("scrollHeight") +" - "+ $('#windows').height());
-               this.scrollBottom();
-               //if(this.div.attr("scrollHeight") > $('#windows').height()){
-               //      touch_scroll.scrollTo(0, this.div.height());
-               //}
-       }
-}
-
-tabview.prototype.scrollBottom = function(){
-       var w = $('#windows');
-       w[0].scrollTop = w[0].scrollHeight;
-}
-
-tabview.prototype.changeNick = function(newNick, oldNick){
-       this.userlist.children().each(function(){
-               var item = $('a.nick', this);
-               if(front.nickStripPrefix(item.text()) == oldNick){
-                       item.text(front.nickGetPrefix(item.text())+newNick);
-                       document.temp_chan = 1;
-               }
-       });
-       
-       if(typeof document.temp_chan != "undefined"){
-               this.addMsg(null, ' ', '=== '+oldNick+' is now known as '+newNick, 'action');
-               delete document.temp_chan;
-               this.userlistSort();
-       }
-}
-
-tabview.prototype.userlistSort = function(){
-       var ul = this.userlist;
-       var listitems = ul.children('li').get();
-       listitems.sort(function(a, b) {
-               var compA = $(a).text().toUpperCase();
-               var compB = $(b).text().toUpperCase();
-               
-               // Sort by prefixes first
-               for (var i in gateway.user_prefixes) {
-                       prefix = gateway.user_prefixes[i].symbol;
-                       
-                       if(compA.charAt(0) == prefix && compB.charAt(0) == prefix){
-                               // Both have the same prefix, string compare time
-                               return 0;
-                       }
-                       
-                       if(compA.charAt(0) == prefix && compB.charAt(0) != prefix){
-                               return -1;
-                       }
-                       
-                       if(compA.charAt(0) != prefix && compB.charAt(0) == prefix){
-                               return 1;
-                       }
-               }
-                          
-               // No prefixes, compare by string
-               return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
-       })
-       $.each(listitems, function(idx, itm) { ul.append(itm); });
-}
-
-tabview.prototype.highlight = function(){
-       this.tab.addClass('highlight');
-}
-tabview.prototype.activity = function(){
-       this.tab.addClass('activity');
-}
-tabview.prototype.clearHighlight = function(){
-       this.tab.removeClass('highlight');
-       this.tab.removeClass('activity');
-}
-tabview.prototype.changeTopic = function(new_topic){
-       this.topic = new_topic;
-       this.addMsg(null, ' ', '=== Topic for '+this.name+' is: '+new_topic, 'topic');
-       if(front.cur_channel.name == this.name) front.setTopicText(new_topic);
-}
-
-
-
-
-
-var box = function(classname){
-       this.id = randomString(10);
-       var tmp = $('<div id="'+this.id+'" class="box '+classname+'"><div class="boxarea"></div></div>');
-       $('#kiwi').append(tmp);
-       this.box = $('#'+this.id);
-       this.content = $('#'+this.id+' .boxarea');
-       
-       this.box.draggable({ stack: ".box" });
-       this.content.click(function(){});
-       //this.box.click(function(){ $(this)..css });
-}
-box.prototype.create = function(name, classname){
-       
-}
-box.prototype.id = null;
-box.prototype.box = null;
-box.prototype.content = null;
-box.prototype.destroy = function(){
-       this.box.remove();
-       for (var name in front.boxes) if(front.boxes[name].id = this.id) delete front.boxes[name];
-}
-box.prototype.height = function(){ return this.box.height(); }
+    line_msg = $('<div class="msg ' + type + '"><div class="time">' + time + '</div><div class="nick">' + html_nick + '</div><div class="text" style="' + style + '">' + msg + ' </div></div>');
+    this.div.append(line_msg);
+
+    if (!touchscreen) {
+        this.scrollBottom();
+    } else {
+        touch_scroll.refresh();
+        //console.log(this.div.attr("scrollHeight") +" - "+ $('#windows').height());
+        this.scrollBottom();
+        //if(this.div.attr("scrollHeight") > $('#windows').height()){
+        //    touch_scroll.scrollTo(0, this.div.height());
+        //}
+    }
+};
+
+Tabview.prototype.scrollBottom = function () {
+    var w = $('#windows');
+    w[0].scrollTop = w[0].scrollHeight;
+};
+
+Tabview.prototype.changeNick = function (newNick, oldNick) {
+    this.userlist.children().each(function () {
+        var item = $('a.nick', this);
+        if (front.nickStripPrefix(item.text()) === oldNick) {
+            item.text(front.nickGetPrefix(item.text()) + newNick);
+            document.temp_chan = 1;
+        }
+    });
+    
+    if (typeof document.temp_chan !== "undefined") {
+        this.addMsg(null, ' ', '=== ' + oldNick + ' is now known as ' + newNick, 'action');
+        delete document.temp_chan;
+        this.userlistSort();
+    }
+};
+
+Tabview.prototype.userlistSort = function () {
+    var ul = this.userlist,
+        listitems = ul.children('li').get();
+    listitems.sort(function (a, b) {
+        var compA = $(a).text().toUpperCase(),
+            compB = $(b).text().toUpperCase(),
+            i;
+        
+        // Sort by prefixes first
+        for (i in gateway.user_prefixes) {
+            prefix = gateway.user_prefixes[i].symbol;
+            
+            if (compA.charAt(0) === prefix && compB.charAt(0) === prefix) {
+                // Both have the same prefix, string compare time
+                return 0;
+            }
+            
+            if (compA.charAt(0) === prefix && compB.charAt(0) !== prefix) {
+                return -1;
+            }
+            
+            if (compA.charAt(0) !== prefix && compB.charAt(0) === prefix) {
+                return 1;
+            }
+        }
+               
+        // No prefixes, compare by string
+        return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
+    });
+    $.each(listitems, function (idx, itm) { ul.append(itm); });
+};
+
+Tabview.prototype.highlight = function () {
+    this.tab.addClass('highlight');
+};
+Tabview.prototype.activity = function () {
+    this.tab.addClass('activity');
+};
+Tabview.prototype.clearHighlight = function () {
+    this.tab.removeClass('highlight');
+    this.tab.removeClass('activity');
+};
+Tabview.prototype.changeTopic = function (new_topic) {
+    this.topic = new_topic;
+    this.addMsg(null, ' ', '=== Topic for ' + this.name + ' is: ' + new_topic, 'topic');
+    if (front.cur_channel.name === this.name) {
+        front.setTopicText(new_topic);
+    }
+};
+
+
+
+
+
+var Box = function (classname) {
+    this.id = randomString(10);
+    var tmp = $('<div id="' + this.id + '" class="box ' + classname + '"><div class="boxarea"></div></div>');
+    $('#kiwi').append(tmp);
+    this.box = $('#' + this.id);
+    this.content = $('#' + this.id + ' .boxarea');
+    
+    this.box.draggable({ stack: ".box" });
+    this.content.click(function () {});
+    //this.box.click(function(){ $(this)..css });
+};
+Box.prototype.create = function (name, classname) {
+    
+};
+Box.prototype.id = null;
+Box.prototype.box = null;
+Box.prototype.content = null;
+Box.prototype.destroy = function () {
+    var name;
+    this.box.remove();
+    for (name in front.boxes) {
+        if (front.boxes[name].id === this.id) {
+            delete front.boxes[name];
+        }
+    }
+};
+Box.prototype.height = function () { 
+    return this.box.height();
+};
index d7fda90f2fb2a2f5e6c7c85fe716a6bd0fc8585a..0ff36cd26da23918dd3222594f20ddf028f85120 100644 (file)
@@ -9,9 +9,9 @@ var gateway = {
     syncing: false,
     channel_prefix: '#',
     network_name: '',
-    user_prefixes: ['~','&','@','+'],
+    user_prefixes: ['~', '&', '@', '+'],
     socket: null,
-       
+    
     start: function (kiwi_server) {
         if (typeof kiwi_server !== 'undefined') {
             gateway.socket = io.connect(kiwi_server);
@@ -33,165 +33,165 @@ var gateway = {
     },
 
     /*
-           Events:
-                   msg
-                   action
-                   server_connect
-                   options
-                   motd
-                   notice
-                   userlist
-                   nick
-                   join
-                   topic
-                   part
-                   kick
-                   quit
-                   whois
-                   syncchannel_redirect
-                   debug
+        Events:
+            msg
+            action
+            server_connect
+            options
+            motd
+            notice
+            userlist
+            nick
+            join
+            topic
+            part
+            kick
+            quit
+            whois
+            syncchannel_redirect
+            debug
     */
     parse: function (item) {
-           if (item.event !== undefined) {
-                   $(gateway).trigger("on" + item.event, item);
-               
-                   switch (item.event) {
-                   case 'options':
-                           $.each(item.options, function (name, value) {
-                                   switch (name) {
-                                   case 'CHANTYPES':
-                                           gateway.channel_prefix = value.charAt(0);
-                                           break;
-                                   case 'NETWORK':
-                                           gateway.network_name = value;
-                                           break;
-                                   case 'PREFIX':
-                                           gateway.user_prefixes = value;
-                                           break;
-                                   }
-                           });
-                           break;
-               
-                   case 'sync':
-                           if (gateway.onSync && gateway.syncing) {
-                                   gateway.syncing = false;
-                                   gateway.onSync(item);
-                           }
-                           break;
-                   }
-           }
+        if (item.event !== undefined) {
+            $(gateway).trigger("on" + item.event, item);
+        
+            switch (item.event) {
+            case 'options':
+                $.each(item.options, function (name, value) {
+                    switch (name) {
+                    case 'CHANTYPES':
+                        gateway.channel_prefix = value.charAt(0);
+                        break;
+                    case 'NETWORK':
+                        gateway.network_name = value;
+                        break;
+                    case 'PREFIX':
+                        gateway.user_prefixes = value;
+                        break;
+                    }
+                });
+                break;
+        
+            case 'sync':
+                if (gateway.onSync && gateway.syncing) {
+                    gateway.syncing = false;
+                    gateway.onSync(item);
+                }
+                break;
+            }
+        }
     },
 
     sendData: function () {},
 
     sync: function (callback) {
-           if (this.session_id === null) {
+        if (this.session_id === null) {
             return;
         }
-       
-           var data = {
-                   method: 'sync',
-                   args: {}
-           };
-       
-           gateway.syncing = true;
-           gateway.sendData(data, callback);
+    
+        var data = {
+            method: 'sync',
+            args: {}
+        };
+    
+        gateway.syncing = true;
+        gateway.sendData(data, callback);
     },
 
     debug: function (callback) {
-           var data = {
-                   method: 'debug',
-                   args: {}
-           };
+        var data = {
+            method: 'debug',
+            args: {}
+        };
 
-           gateway.sendData(data, callback);
+        gateway.sendData(data, callback);
     },
 
 
     msg: function (s_target, s_msg, callback) {
-           var data = {
-                   method: 'msg',
-                   args: {
-                           target: s_target,
-                           msg: s_msg
-                   }
-           };
-
-           gateway.sendData(data, callback);
+        var data = {
+            method: 'msg',
+            args: {
+                target: s_target,
+                msg: s_msg
+            }
+        };
+
+        gateway.sendData(data, callback);
     },
 
     action: function (s_target, s_msg, callback) {
-           var data = {
-                   method: 'action',
-                   args: {
-                           target: s_target,
-                           msg: s_msg
-                   }
-           };
-
-           gateway.sendData(data, callback);
+        var data = {
+            method: 'action',
+            args: {
+                target: s_target,
+                msg: s_msg
+            }
+        };
+
+        gateway.sendData(data, callback);
     },
 
 
     notice: function (s_target, s_msg, callback) {
-           var data = {
-                   method: 'notice',
-                   args: {
-                           target: s_target,
-                           msg: s_msg
-                   }
-           };
-
-           gateway.sendData(data, callback);
+        var data = {
+            method: 'notice',
+            args: {
+                target: s_target,
+                msg: s_msg
+            }
+        };
+
+        gateway.sendData(data, callback);
     },
 
 
     join: function (s_channel, callback) {
-           var data = {
-                   method: 'join',
-                   args: {
-                           channel: s_channel
-                   }
-           };
-
-           gateway.sendData(data, callback);
+        var data = {
+            method: 'join',
+            args: {
+                channel: s_channel
+            }
+        };
+
+        gateway.sendData(data, callback);
     },
 
-    setTopic: function (s_channel, new_topic, callback){
-           var data = {
-                   method: 'topic',
-                   args: {
-                           channel: s_channel,
-                           topic: new_topic
-                   }
-           };
+    setTopic: function (s_channel, new_topic, callback) {
+        var data = {
+            method: 'topic',
+            args: {
+                channel: s_channel,
+                topic: new_topic
+            }
+        };
 
-           gateway.sendData(data, callback);
+        gateway.sendData(data, callback);
     },
 
 
     raw: function (v_data, callback) {
-           var data = {
-                   method: 'raw',
-                   args: {
-                           data: v_data
-                   }
-           };
-
-           gateway.sendData(data, callback);
+        var data = {
+            method: 'raw',
+            args: {
+                data: v_data
+            }
+        };
+
+        gateway.sendData(data, callback);
     },
 
 
     quit: function (msg, callback) {
-           //alert("closing");
-           msg = msg || "";
-           var data = {
-                   method: 'quit',
-                   args: {
-                           message: msg
-                   }
-           };
-       
+        //alert("closing");
+        msg = msg || "";
+        var data = {
+            method: 'quit',
+            args: {
+                message: msg
+            }
+        };
+    
         gateway.sendData(data, callback);
     }
 
index 3dc0e65a9a7a0d4664be86b549b9693d24d0cf60..3411196e2d5105f7ff5b970f7bd6f6e367cf4ae6 100644 (file)
@@ -1,19 +1,18 @@
-/*jslint regexp: true, confusion: true, undef: false, node: true, sloppy: true, nomen: true, plusplus: true, maxerr: 50, indent: 4 */
+/*jslint continue: true, forin: true, regexp: true, confusion: true, undef: false, node: true, sloppy: true, nomen: true, plusplus: true, maxerr: 50, indent: 4 */
 
 var tls = require('tls'),
-       net = require('net'),
-       http = require('http'),
-       https = require('https'),
-       fs = require('fs'),
-       url = require('url'),
-       ws = require('socket.io'),
-       _ = require('./lib/underscore.min.js'),
-       starttls = require('./lib/starttls.js'),
-       kiwi_mod = require('./lib/kiwi_mod.js');
+    net = require('net'),
+    http = require('http'),
+    https = require('https'),
+    fs = require('fs'),
+    url = require('url'),
+    ws = require('socket.io'),
+    _ = require('./lib/underscore.min.js'),
+    starttls = require('./lib/starttls.js');
 
-       // Libraries may need to know kiwi.js path as __dirname
-       // only gives that librarys path. Set it here for usage later.
-       kiwi_root = __dirname;
+// Libraries may need to know kiwi.js path as __dirname
+// only gives that librarys path. Set it here for usage later.
+var kiwi_root = __dirname;
 
 
 /*
@@ -21,31 +20,36 @@ var tls = require('tls'),
  * - /etc/kiwi/config.json
  * - ./config.json
  */
-config = null, config_filename = 'config.json';
-var config_dirs = ['/etc/kiwiirc/', __dirname + '/'];
-for(var i in config_dirs){
-       try {
-               if(fs.lstatSync(config_dirs[i] + config_filename).isDirectory() === false){
-                       config = JSON.parse(fs.readFileSync(config_dirs[i] + config_filename, 'ascii'));
-                       console.log('Using config file ' + config_dirs[i] + config_filename);
-                       break;
-               }
-       } catch(e){
-               continue;
-       }
-}
-
-if(config === null){
-       console.log('Couldn\'t find a config file!');
-       process.exit(0);
-}
-
+var config = null,
+    config_filename = 'config.json',
+    config_dirs = ['/etc/kiwiirc/', __dirname + '/'];
+
+(function () {
+    var i;
+    for (i in config_dirs) {
+        try {
+            if (fs.lstatSync(config_dirs[i] + config_filename).isDirectory() === false) {
+                config = JSON.parse(fs.readFileSync(config_dirs[i] + config_filename, 'ascii'));
+                console.log('Using config file ' + config_dirs[i] + config_filename);
+                break;
+            }
+        } catch (e) {
+            continue;
+        }
+    }
+
+    if (config === null) {
+        console.log('Couldn\'t find a config file!');
+        process.exit(0);
+    }
+}());
 
 
 /*
  * Load the modules as set in the config and print them out
  */
-kiwi_mod.loadModules();
+var kiwi_mod = require('./lib/kiwi_mod.js');
+kiwi_mod.loadModules(kiwi_root, config);
 kiwi_mod.printMods();
 
 
@@ -55,27 +59,25 @@ kiwi_mod.printMods();
  * Some process changes
  */
 process.title = 'kiwiirc';
-function changeUser(){
-       if(typeof config.group !== 'undefined' && config.group !== ''){
-               try {
-                       process.setgid(config.group);
-               }
-               catch (err) {
-                       console.log('Failed to set gid: ' + err);
-                       process.exit();
-               }
-       }
-
-       if(typeof config.user !== 'undefined' && config.user !== ''){
-               try {
-                       process.setuid(config.user);
-               }
-               catch (err) {
-                       console.log('Failed to set uid: ' + err);
-                       process.exit();
-               }
-       }
-}
+var changeUser = function () {
+    if (typeof config.group !== 'undefined' && config.group !== '') {
+        try {
+            process.setgid(config.group);
+        } catch (err) {
+            console.log('Failed to set gid: ' + err);
+            process.exit();
+        }
+    }
+
+    if (typeof config.user !== 'undefined' && config.user !== '') {
+        try {
+            process.setuid(config.user);
+        } catch (e) {
+            console.log('Failed to set uid: ' + e);
+            process.exit();
+        }
+    }
+};
 
 
 /*
@@ -84,408 +86,407 @@ function changeUser(){
  */
 
 var ircNumerics = {
-       RPL_WELCOME:            '001',
-       RPL_ISUPPORT:           '005',
-       RPL_WHOISUSER:          '311',
-       RPL_WHOISSERVER:        '312',
-       RPL_WHOISOPERATOR:      '313',
-       RPL_WHOISIDLE:          '317',
-       RPL_ENDOFWHOIS:         '318',
-       RPL_WHOISCHANNELS:      '319',
-       RPL_NOTOPIC:            '331',
-       RPL_TOPIC:              '332',
-       RPL_NAMEREPLY:          '353',
-       RPL_ENDOFNAMES:         '366',
-       RPL_MOTD:               '372',
-       RPL_WHOISMODES:         '379',
-       ERR_NOSUCHNICK:         '401',
-       ERR_CANNOTSENDTOCHAN:   '404',
-       ERR_TOOMANYCHANNELS:    '405',
-       ERR_USERNOTINCHANNEL:   '441',
-       ERR_NOTONCHANNEL:       '442',
-       ERR_LINKCHANNEL:        '470',
-       ERR_CHANNELISFULL:      '471',
-       ERR_INVITEONLYCHAN:     '473',
-       ERR_BANNEDFROMCHAN:     '474',
-       ERR_BADCHANNELKEY:      '475',
-       ERR_LINKCHANNEL:        '470',
-       ERR_CHANOPRIVSNEEDED:   '482',
-       RPL_STARTTLS:           '670'
+    RPL_WELCOME:            '001',
+    RPL_ISUPPORT:           '005',
+    RPL_WHOISUSER:          '311',
+    RPL_WHOISSERVER:        '312',
+    RPL_WHOISOPERATOR:      '313',
+    RPL_WHOISIDLE:          '317',
+    RPL_ENDOFWHOIS:         '318',
+    RPL_WHOISCHANNELS:      '319',
+    RPL_NOTOPIC:            '331',
+    RPL_TOPIC:              '332',
+    RPL_NAMEREPLY:          '353',
+    RPL_ENDOFNAMES:         '366',
+    RPL_MOTD:               '372',
+    RPL_WHOISMODES:         '379',
+    ERR_NOSUCHNICK:         '401',
+    ERR_CANNOTSENDTOCHAN:   '404',
+    ERR_TOOMANYCHANNELS:    '405',
+    ERR_USERNOTINCHANNEL:   '441',
+    ERR_NOTONCHANNEL:       '442',
+    ERR_LINKCHANNEL:        '470',
+    ERR_CHANNELISFULL:      '471',
+    ERR_INVITEONLYCHAN:     '473',
+    ERR_BANNEDFROMCHAN:     '474',
+    ERR_BADCHANNELKEY:      '475',
+    ERR_CHANOPRIVSNEEDED:   '482',
+    RPL_STARTTLS:           '670'
 };
 
 
 
 
 var parseIRCMessage = function (websocket, ircSocket, data) {
-       /*global ircSocketDataHandler */
-       var msg, regex, opts, options, opt, i, j, matches, nick, users, chan, params, prefix, prefixes, nicklist, caps, rtn;
-       regex = /^(?::(?:([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)|([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)!([a-z0-9~\.\-_|]+)@([a-z0-9\.\-:]+)) )?([a-z0-9]+)(?:(?: ([^:]+))?(?: :(.+))?)$/i;
-       msg = regex.exec(data);
-       if (msg) {
-               msg = {
-                       prefix:     msg[1],
-                       nick:       msg[2],
-                       ident:      msg[3],
-                       hostname:   msg[4],
-                       command:    msg[5],
-                       params:     msg[6] || '',
-                       trailing:   (msg[7]) ? msg[7].trim() : ''
-               };
-               switch (msg.command.toUpperCase()) {
-               case 'PING':
-                       websocket.sendServerLine('PONG ' + msg.trailing);
-                       break;
-               case ircNumerics.RPL_WELCOME:
-                       if (ircSocket.IRC.CAP.negotiating) {
-                               ircSocket.IRC.CAP.negotiating = false;
-                               ircSocket.IRC.CAP.enabled = [];
-                               ircSocket.IRC.CAP.requested = [];
-                       }
-                       websocket.sendClientEvent('connect', {connected: true, host: null});
-                       break;
-               case ircNumerics.RPL_ISUPPORT:
-                       opts = msg.params.split(" ");
-                       options = [];
-                       for (i = 0; i < opts.length; i++) {
-                               opt = opts[i].split("=", 2);
-                               opt[0] = opt[0].toUpperCase();
-                               ircSocket.IRC.options[opt[0]] = opt[1] || true;
-                               if (_.include(['NETWORK', 'PREFIX', 'CHANTYPES'], opt[0])) {
-                                       if (opt[0] === 'PREFIX') {
-                                               regex = /\(([^)]*)\)(.*)/;
-                                               matches = regex.exec(opt[1]);
-                                               if ((matches) && (matches.length === 3)) {
-                                                       ircSocket.IRC.options[opt[0]] = [];
-                                                       for (j = 0; j < matches[2].length; j++) {
-                                                               //ircSocket.IRC.options[opt[0]][matches[2].charAt(j)] = matches[1].charAt(j);
-                                                               ircSocket.IRC.options[opt[0]].push({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
-                                                               //console.log({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
-                                                       }
-                                                       console.log(ircSocket.IRC.options);
-                                               }
-                                       }
-                               }
-                       }
-                       websocket.sendClientEvent('options', {server: '', "options": ircSocket.IRC.options});
-                       break;
-               case ircNumerics.RPL_WHOISUSER:
-               case ircNumerics.RPL_WHOISSERVER:
-               case ircNumerics.RPL_WHOISOPERATOR:
-               case ircNumerics.RPL_ENDOFWHOIS:
-               case ircNumerics.RPL_WHOISCHANNELS:
-               case ircNumerics.RPL_WHOISMODES:
-                       websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing});
-                       break;
-               case ircNumerics.RPL_WHOISIDLE:
-                       params = msg.params.split(" ", 4);
-                       rtn = {server: '', nick: params[1], idle: params[2]};
-                       if (params[3]) {
-                               rtn.logon = params[3];
-                       }
-                       websocket.sendClientEvent('whois', rtn);
-                       break;
-               case ircNumerics.RPL_MOTD:
-                       websocket.sendClientEvent('motd', {server: '', "msg": msg.trailing});
-                       break;
-               case ircNumerics.RPL_NAMEREPLY:
-                       params = msg.params.split(" ");
-                       nick = params[0];
-                       chan = params[2];
-                       users = msg.trailing.split(" ");
-                       prefixes = _.values(ircSocket.IRC.options.PREFIX);
-                       nicklist = {};
-                       i = 0;
-                       _.each(users, function (user) {
-                               if (_.include(prefix, user.charAt(0))) {
-                                       prefix = user.charAt(0);
-                                       user = user.substring(1);
-                                       nicklist[user] = prefix;
-                               } else {
-                                       nicklist[user] = '';
-                               }
-                               if (i++ >= 50) {
-                                       websocket.sendClientEvent('userlist', {server: '', 'users': nicklist, channel: chan});
-                                       nicklist = {};
-                                       i = 0;
-                               }
-                       });
-                       if (i > 0) {
-                               websocket.sendClientEvent('userlist', {server: '', "users": nicklist, channel: chan});
-                       } else {
-                               console.log("oops");
-                       }
-                       break;
-               case ircNumerics.RPL_ENDOFNAMES:
-                       websocket.sendClientEvent('userlist_end', {server: '', channel: msg.params.split(" ")[1]});
-                       break;
-               case ircNumerics.ERR_LINKCHANNEL:
-                       params = msg.params.split(" "); 
-                       websocket.sendClientEvent('channel_redirect', {from: params[1], to: params[2]});
-                       break;
-               case ircNumerics.ERR_NOSUCHNICK:
-                       websocket.sendClientEvent('irc_error', {error: 'no_such_nick', nick: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               case 'JOIN':
-                       websocket.sendClientEvent('join', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.trailing});
-                       if (msg.nick === ircSocket.IRC.nick) {
-                               websocket.sendServerLine('NAMES ' + msg.trailing);
-                       }
-                       break;
-               case 'PART':
-                       websocket.sendClientEvent('part', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), message: msg.trailing});
-                       break;
-               case 'KICK':
-                       params = msg.params.split(" ");
-                       websocket.sendClientEvent('kick', {kicked: params[1], nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: params[0].trim(), message: msg.trailing});
-                       break;
-               case 'QUIT':
-                       websocket.sendClientEvent('quit', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, message: msg.trailing});
-                       break;
-               case 'NOTICE':
-                       if ((msg.trailing.charAt(0) === '\001') && (msg.trailing.charAt(msg.trailing.length - 1) === '\001')) {
-                               // It's a CTCP response
-                               websocket.sendClientEvent('ctcp_response', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing.substr(1, msg.trailing.length - 2)});
-                       } else {
-                               websocket.sendClientEvent('notice', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing});
-                       }
-                       break;
-               case 'NICK':
-                       websocket.sendClientEvent('nick', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, newnick: msg.trailing});
-                       break;
-               case 'TOPIC':
-                       var obj = {nick: msg.nick, channel: msg.params, topic: msg.trailing};
-                       websocket.sendClientEvent('topic', obj);
-                       break;
-               case ircNumerics.RPL_TOPIC:
-                       var obj = {nick: '', channel: msg.params.split(" ")[1], topic: msg.trailing};
-                       websocket.sendClientEvent('topic', obj);
-                       break;
-               case ircNumerics.RPL_NOTOPIC:
-                       var obj = {nick: '', channel: msg.params.split(" ")[1], topic:''};
-                       websocket.sendClientEvent('topic', obj);
-                       break;
-               case 'MODE':
-                       opts = msg.params.split(" ");
-                       params = {nick: msg.nick};
-                       switch (opts.length) {
-                       case 1:
-                               params.effected_nick = opts[0];
-                               params.mode = msg.trailing;
-                               break;
-                       case 2:
-                               params.channel = opts[0];
-                               params.mode = opts[1];
-                               break;
-                       default:
-                               params.channel = opts[0];
-                               params.mode = opts[1];
-                               params.effected_nick = opts[2];
-                               break;
-                       }
-                       websocket.sendClientEvent('mode', params);
-                       break;
-               case 'PRIVMSG':
-                       if ((msg.trailing.charAt(0) === '\001') && (msg.trailing.charAt(msg.trailing.length - 1) === '\001')) {
-                               // It's a CTCP request
-                               if (msg.trailing.substr(1, 6) === 'ACTION') {
-                                       websocket.sendClientEvent('action', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing.substr(7, msg.trailing.length - 2)});
-                               } else if (msg.trailing.substr(1, 7) === 'VERSION') {
-                                       ircSocket.write('NOTICE ' + msg.nick + ' :\001VERSION KiwiIRC\001\r\n');
-                               } else {
-                                       websocket.sendClientEvent('ctcp_request', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing.substr(1, msg.trailing.length - 2)});
-                               }
-                       } else {
-                               var obj = {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing};
-                               websocket.sendClientEvent('msg', obj);
-                       }
-                       break;
-               case 'CAP':
-                       caps = config.cap_options;
-                       options = msg.trailing.split(" ");
-                       switch (_.first(msg.params.split(" "))) {
-                       case 'LS':
-                               opts = '';
-                               _.each(_.intersect(caps, options), function (cap) {
-                                       if (opts !== '') {
-                                               opts += " ";
-                                       }
-                                       opts += cap;
-                                       ircSocket.IRC.CAP.requested.push(cap);
-                               });
-                               if (opts.length > 0) {
-                                       websocket.sendServerLine('CAP REQ :' + opts);
-                               } else {
-                                       websocket.sendServerLine('CAP END');
-                               }
-                               // TLS is special
-                               /*if (_.include(options, 'tls')) {
-                                       websocket.sendServerLine('STARTTLS');
-                                       ircSocket.IRC.CAP.requested.push('tls');
-                               }*/
-                               break;
-                       case 'ACK':
-                               _.each(options, function (cap) {
-                                       ircSocket.IRC.CAP.enabled.push(cap);
-                               });
-                               if (_.last(msg.params.split(" ")) !== '*') {
-                                       ircSocket.IRC.CAP.requested = [];
-                                       ircSocket.IRC.CAP.negotiating = false;
-                                       websocket.sendServerLine('CAP END');
-                               }
-                               break;
-                       case 'NAK':
-                               ircSocket.IRC.CAP.requested = [];
-                               ircSocket.IRC.CAP.negotiating = false;
-                               websocket.sendServerLine('CAP END');
-                               break;
-                       }
-                       break;
-               /*case ircNumerics.RPL_STARTTLS:
-                       try {
-                               IRC = ircSocket.IRC;
-                               listeners = ircSocket.listeners('data');
-                               ircSocket.removeAllListeners('data');
-                               ssl_socket = starttls(ircSocket, {}, function () {
-                                       ssl_socket.on("data", function (data) {
-                                               ircSocketDataHandler(data, websocket, ssl_socket);
-                                       });
-                                       ircSocket = ssl_socket;
-                                       ircSocket.IRC = IRC;
-                                       _.each(listeners, function (listener) {
-                                               ircSocket.addListener('data', listener);
-                                       });
-                               });
-                               //console.log(ircSocket);
-                       } catch (e) {
-                               console.log(e);
-                       }
-                       break;*/
-               case ircNumerics.ERR_CANNOTSENDTOCHAN:
-                       websocket.sendClientEvent('irc_error', {error: 'cannot_send_to_chan', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               case ircNumerics.ERR_TOOMANYCHANNELS:
-                       websocket.sendClientEvent('irc_error', {error: 'too_many_channels', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               case ircNumerics.ERR_USERNOTINCHANNEL:
-                       params = msg.params.split(" ");
-                       websocket.sendClientEvent('irc_error', {error: 'user_not_in_channel', nick: params[0], channel: params[1], reason: msg.trainling});
-                       break;
-               case ircNumerics.ERR_NOTONCHANNEL:
-                       websocket.sendClientEvent('irc_error', {error: 'not_on_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               case ircNumerics.ERR_CHANNELISFULL:
-                       websocket.sendClientEvent('irc_error', {error: 'channel_is_full', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               case ircNumerics.ERR_INVITEONLYCHAN:
-                       websocket.sendClientEvent('irc_error', {error: 'invite_only_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               case ircNumerics.ERR_BANNEDFROMCHAN:
-                       websocket.sendClientEvent('irc_error', {error: 'banned_from_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               case ircNumerics.ERR_BADCHANNELKEY:
-                       websocket.sendClientEvent('irc_error', {error: 'bad_channel_key', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               case ircNumerics.ERR_CHANOPRIVSNEEDED:
-                       websocket.sendClientEvent('irc_error', {error: 'chanop_privs_needed', channel: msg.params.split(" ")[1], reason: msg.trailing});
-                       break;
-               }
-       } else {
-               console.log("Unknown command.\r\n");
-       }
+    /*global ircSocketDataHandler */
+    var msg, regex, opts, options, opt, i, j, matches, nick, users, chan, params, prefix, prefixes, nicklist, caps, rtn, obj;
+    regex = /^(?::(?:([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)|([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)!([a-z0-9~\.\-_|]+)@([a-z0-9\.\-:]+)) )?([a-z0-9]+)(?:(?: ([^:]+))?(?: :(.+))?)$/i;
+    msg = regex.exec(data);
+    if (msg) {
+        msg = {
+            prefix:     msg[1],
+            nick:       msg[2],
+            ident:      msg[3],
+            hostname:   msg[4],
+            command:    msg[5],
+            params:     msg[6] || '',
+            trailing:   (msg[7]) ? msg[7].trim() : ''
+        };
+        switch (msg.command.toUpperCase()) {
+        case 'PING':
+            websocket.sendServerLine('PONG ' + msg.trailing);
+            break;
+        case ircNumerics.RPL_WELCOME:
+            if (ircSocket.IRC.CAP.negotiating) {
+                ircSocket.IRC.CAP.negotiating = false;
+                ircSocket.IRC.CAP.enabled = [];
+                ircSocket.IRC.CAP.requested = [];
+            }
+            websocket.sendClientEvent('connect', {connected: true, host: null});
+            break;
+        case ircNumerics.RPL_ISUPPORT:
+            opts = msg.params.split(" ");
+            options = [];
+            for (i = 0; i < opts.length; i++) {
+                opt = opts[i].split("=", 2);
+                opt[0] = opt[0].toUpperCase();
+                ircSocket.IRC.options[opt[0]] = opt[1] || true;
+                if (_.include(['NETWORK', 'PREFIX', 'CHANTYPES'], opt[0])) {
+                    if (opt[0] === 'PREFIX') {
+                        regex = /\(([^)]*)\)(.*)/;
+                        matches = regex.exec(opt[1]);
+                        if ((matches) && (matches.length === 3)) {
+                            ircSocket.IRC.options[opt[0]] = [];
+                            for (j = 0; j < matches[2].length; j++) {
+                                //ircSocket.IRC.options[opt[0]][matches[2].charAt(j)] = matches[1].charAt(j);
+                                ircSocket.IRC.options[opt[0]].push({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
+                                //console.log({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
+                            }
+                            console.log(ircSocket.IRC.options);
+                        }
+                    }
+                }
+            }
+            websocket.sendClientEvent('options', {server: '', "options": ircSocket.IRC.options});
+            break;
+        case ircNumerics.RPL_WHOISUSER:
+        case ircNumerics.RPL_WHOISSERVER:
+        case ircNumerics.RPL_WHOISOPERATOR:
+        case ircNumerics.RPL_ENDOFWHOIS:
+        case ircNumerics.RPL_WHOISCHANNELS:
+        case ircNumerics.RPL_WHOISMODES:
+            websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing});
+            break;
+        case ircNumerics.RPL_WHOISIDLE:
+            params = msg.params.split(" ", 4);
+            rtn = {server: '', nick: params[1], idle: params[2]};
+            if (params[3]) {
+                rtn.logon = params[3];
+            }
+            websocket.sendClientEvent('whois', rtn);
+            break;
+        case ircNumerics.RPL_MOTD:
+            websocket.sendClientEvent('motd', {server: '', "msg": msg.trailing});
+            break;
+        case ircNumerics.RPL_NAMEREPLY:
+            params = msg.params.split(" ");
+            nick = params[0];
+            chan = params[2];
+            users = msg.trailing.split(" ");
+            prefixes = _.values(ircSocket.IRC.options.PREFIX);
+            nicklist = {};
+            i = 0;
+            _.each(users, function (user) {
+                if (_.include(prefix, user.charAt(0))) {
+                    prefix = user.charAt(0);
+                    user = user.substring(1);
+                    nicklist[user] = prefix;
+                } else {
+                    nicklist[user] = '';
+                }
+                if (i++ >= 50) {
+                    websocket.sendClientEvent('userlist', {server: '', 'users': nicklist, channel: chan});
+                    nicklist = {};
+                    i = 0;
+                }
+            });
+            if (i > 0) {
+                websocket.sendClientEvent('userlist', {server: '', "users": nicklist, channel: chan});
+            } else {
+                console.log("oops");
+            }
+            break;
+        case ircNumerics.RPL_ENDOFNAMES:
+            websocket.sendClientEvent('userlist_end', {server: '', channel: msg.params.split(" ")[1]});
+            break;
+        case ircNumerics.ERR_LINKCHANNEL:
+            params = msg.params.split(" "); 
+            websocket.sendClientEvent('channel_redirect', {from: params[1], to: params[2]});
+            break;
+        case ircNumerics.ERR_NOSUCHNICK:
+            websocket.sendClientEvent('irc_error', {error: 'no_such_nick', nick: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        case 'JOIN':
+            websocket.sendClientEvent('join', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.trailing});
+            if (msg.nick === ircSocket.IRC.nick) {
+                websocket.sendServerLine('NAMES ' + msg.trailing);
+            }
+            break;
+        case 'PART':
+            websocket.sendClientEvent('part', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), message: msg.trailing});
+            break;
+        case 'KICK':
+            params = msg.params.split(" ");
+            websocket.sendClientEvent('kick', {kicked: params[1], nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: params[0].trim(), message: msg.trailing});
+            break;
+        case 'QUIT':
+            websocket.sendClientEvent('quit', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, message: msg.trailing});
+            break;
+        case 'NOTICE':
+            if ((msg.trailing.charAt(0) === String.fromCharCode(1)) && (msg.trailing.charAt(msg.trailing.length - 1) === String.fromCharCode(1))) {
+                // It's a CTCP response
+                websocket.sendClientEvent('ctcp_response', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing.substr(1, msg.trailing.length - 2)});
+            } else {
+                websocket.sendClientEvent('notice', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing});
+            }
+            break;
+        case 'NICK':
+            websocket.sendClientEvent('nick', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, newnick: msg.trailing});
+            break;
+        case 'TOPIC':
+            obj = {nick: msg.nick, channel: msg.params, topic: msg.trailing};
+            websocket.sendClientEvent('topic', obj);
+            break;
+        case ircNumerics.RPL_TOPIC:
+            obj = {nick: '', channel: msg.params.split(" ")[1], topic: msg.trailing};
+            websocket.sendClientEvent('topic', obj);
+            break;
+        case ircNumerics.RPL_NOTOPIC:
+            obj = {nick: '', channel: msg.params.split(" ")[1], topic: ''};
+            websocket.sendClientEvent('topic', obj);
+            break;
+        case 'MODE':
+            opts = msg.params.split(" ");
+            params = {nick: msg.nick};
+            switch (opts.length) {
+            case 1:
+                params.effected_nick = opts[0];
+                params.mode = msg.trailing;
+                break;
+            case 2:
+                params.channel = opts[0];
+                params.mode = opts[1];
+                break;
+            default:
+                params.channel = opts[0];
+                params.mode = opts[1];
+                params.effected_nick = opts[2];
+                break;
+            }
+            websocket.sendClientEvent('mode', params);
+            break;
+        case 'PRIVMSG':
+            if ((msg.trailing.charAt(0) === String.fromCharCode(1)) && (msg.trailing.charAt(msg.trailing.length - 1) === String.fromCharCode(1))) {
+                // It's a CTCP request
+                if (msg.trailing.substr(1, 6) === 'ACTION') {
+                    websocket.sendClientEvent('action', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing.substr(7, msg.trailing.length - 2)});
+                } else if (msg.trailing.substr(1, 7) === 'VERSION') {
+                    ircSocket.write('NOTICE ' + msg.nick + ' :' + String.fromCharCode(1) + 'VERSION KiwiIRC' + String.fromCharCode(1) + '\r\n');
+                } else {
+                    websocket.sendClientEvent('ctcp_request', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing.substr(1, msg.trailing.length - 2)});
+                }
+            } else {
+                obj = {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing};
+                websocket.sendClientEvent('msg', obj);
+            }
+            break;
+        case 'CAP':
+            caps = config.cap_options;
+            options = msg.trailing.split(" ");
+            switch (_.first(msg.params.split(" "))) {
+            case 'LS':
+                opts = '';
+                _.each(_.intersect(caps, options), function (cap) {
+                    if (opts !== '') {
+                        opts += " ";
+                    }
+                    opts += cap;
+                    ircSocket.IRC.CAP.requested.push(cap);
+                });
+                if (opts.length > 0) {
+                    websocket.sendServerLine('CAP REQ :' + opts);
+                } else {
+                    websocket.sendServerLine('CAP END');
+                }
+                // TLS is special
+                /*if (_.include(options, 'tls')) {
+                    websocket.sendServerLine('STARTTLS');
+                    ircSocket.IRC.CAP.requested.push('tls');
+                }*/
+                break;
+            case 'ACK':
+                _.each(options, function (cap) {
+                    ircSocket.IRC.CAP.enabled.push(cap);
+                });
+                if (_.last(msg.params.split(" ")) !== '*') {
+                    ircSocket.IRC.CAP.requested = [];
+                    ircSocket.IRC.CAP.negotiating = false;
+                    websocket.sendServerLine('CAP END');
+                }
+                break;
+            case 'NAK':
+                ircSocket.IRC.CAP.requested = [];
+                ircSocket.IRC.CAP.negotiating = false;
+                websocket.sendServerLine('CAP END');
+                break;
+            }
+            break;
+        /*case ircNumerics.RPL_STARTTLS:
+            try {
+                IRC = ircSocket.IRC;
+                listeners = ircSocket.listeners('data');
+                ircSocket.removeAllListeners('data');
+                ssl_socket = starttls(ircSocket, {}, function () {
+                    ssl_socket.on("data", function (data) {
+                        ircSocketDataHandler(data, websocket, ssl_socket);
+                    });
+                    ircSocket = ssl_socket;
+                    ircSocket.IRC = IRC;
+                    _.each(listeners, function (listener) {
+                        ircSocket.addListener('data', listener);
+                    });
+                });
+                //console.log(ircSocket);
+            } catch (e) {
+                console.log(e);
+            }
+            break;*/
+        case ircNumerics.ERR_CANNOTSENDTOCHAN:
+            websocket.sendClientEvent('irc_error', {error: 'cannot_send_to_chan', channel: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        case ircNumerics.ERR_TOOMANYCHANNELS:
+            websocket.sendClientEvent('irc_error', {error: 'too_many_channels', channel: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        case ircNumerics.ERR_USERNOTINCHANNEL:
+            params = msg.params.split(" ");
+            websocket.sendClientEvent('irc_error', {error: 'user_not_in_channel', nick: params[0], channel: params[1], reason: msg.trainling});
+            break;
+        case ircNumerics.ERR_NOTONCHANNEL:
+            websocket.sendClientEvent('irc_error', {error: 'not_on_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        case ircNumerics.ERR_CHANNELISFULL:
+            websocket.sendClientEvent('irc_error', {error: 'channel_is_full', channel: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        case ircNumerics.ERR_INVITEONLYCHAN:
+            websocket.sendClientEvent('irc_error', {error: 'invite_only_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        case ircNumerics.ERR_BANNEDFROMCHAN:
+            websocket.sendClientEvent('irc_error', {error: 'banned_from_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        case ircNumerics.ERR_BADCHANNELKEY:
+            websocket.sendClientEvent('irc_error', {error: 'bad_channel_key', channel: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        case ircNumerics.ERR_CHANOPRIVSNEEDED:
+            websocket.sendClientEvent('irc_error', {error: 'chanop_privs_needed', channel: msg.params.split(" ")[1], reason: msg.trailing});
+            break;
+        }
+    } else {
+        console.log("Unknown command.\r\n");
+    }
 };
 
 var ircSocketDataHandler = function (data, websocket, ircSocket) {
-       var i;
-       if ((ircSocket.holdLast) && (ircSocket.held !== '')) {
-               data = ircSocket.held + data;
-               ircSocket.holdLast = false;
-               ircSocket.held = '';
-       }
-       if (data.substr(-2) === '\r\n') {
-               ircSocket.holdLast = true;
-       }
-       data = data.split("\r\n");         
-       for (i = 0; i < data.length; i++) {
-               if (data[i]) {
-                       if ((ircSocket.holdLast) && (i === data.length - 1)) {
-                               ircSocket.held = data[i];
-                               break;
-                       }
-                       console.log("->" + data[i]);
-                       parseIRCMessage(websocket, ircSocket, data[i]);
-               }
-       }
+    var i;
+    if ((ircSocket.holdLast) && (ircSocket.held !== '')) {
+        data = ircSocket.held + data;
+        ircSocket.holdLast = false;
+        ircSocket.held = '';
+    }
+    if (data.substr(-2) === '\r\n') {
+        ircSocket.holdLast = true;
+    }
+    data = data.split("\r\n");         
+    for (i = 0; i < data.length; i++) {
+        if (data[i]) {
+            if ((ircSocket.holdLast) && (i === data.length - 1)) {
+                ircSocket.held = data[i];
+                break;
+            }
+            console.log("->" + data[i]);
+            parseIRCMessage(websocket, ircSocket, data[i]);
+        }
+    }
 };
 
 if (config.handle_http) {
-       var fileServer = new (require('node-static').Server)(__dirname + config.public_http);
-       var jade = require('jade');
+    var fileServer = new (require('node-static').Server)(__dirname + config.public_http);
+    var jade = require('jade');
 }
 
 var httpHandler = function (request, response) {
-       var uri, subs, useragent, agent, server_set, server, nick, debug, touchscreen;
-       if (config.handle_http) {
-               uri = url.parse(request.url);
-               subs = uri.pathname.substr(0, 4);
-               if ((subs === '/js/') || (subs === '/css') || (subs === '/img')) {
-                       request.addListener('end', function () {
-                               fileServer.serve(request, response);
-                       });
-               } else if (uri.pathname === '/') {
-                       useragent = (response.headers) ? response.headers['user-agent']: '';
-                       if (useragent.indexOf('android') !== -1) {
-                               agent = 'android';
-                               touchscreen = true;
-                       } else if (useragent.indexOf('iphone') !== -1) {
-                               agent = 'iphone';
-                               touchscreen = true;
-                       } else if (useragent.indexOf('ipad') !== -1) {
-                               agent = 'ipad';
-                               touchscreen = true;
-                       } else if (useragent.indexOf('ipod') !== -1) {
-                               agent = 'ipod';
-                               touchscreen = true;
-                       } else {
-                               agent = 'normal';
-                               touchscreen = false;
-                       }
-                       if (uri.query) {
-                               server_set = (uri.query.server !== '');
-                               server = uri.query.server || 'irc.anonnet.org';
-                               nick = uri.query.nick || '';
-                               debug = (uri.query.debug !== '');
-                       } else {
-                               server = 'irc.anonnet.org';
-                               nick = '';
-                       }
-                       response.setHeader('Connection', 'close');
-                       response.setHeader('X-Generated-By', 'KiwiIRC');
-                       jade.renderFile(__dirname + '/client/index.html.jade', { locals: { "touchscreen": touchscreen, "debug": debug, "server_set": server_set, "server": server, "nick": nick, "agent": agent, "config": config }}, function (err, html) {
-                               if (!err) {
-                                       response.write(html);
-                               } else {
-                                       response.statusCode = 500;
-                               }
-                               response.end();
-                       });
-               } else if (uri.pathname.substr(0, 10) === '/socket.io') {
-                       // Do nothing!
-               } else {
-                       response.statusCode = 404;
-                       response.end();
-               }
-       }
+    var uri, subs, useragent, agent, server_set, server, nick, debug, touchscreen;
+    if (config.handle_http) {
+        uri = url.parse(request.url);
+        subs = uri.pathname.substr(0, 4);
+        if ((subs === '/js/') || (subs === '/css') || (subs === '/img')) {
+            request.addListener('end', function () {
+                fileServer.serve(request, response);
+            });
+        } else if (uri.pathname === '/') {
+            useragent = (response.headers) ? response.headers['user-agent'] : '';
+            if (useragent.indexOf('android') !== -1) {
+                agent = 'android';
+                touchscreen = true;
+            } else if (useragent.indexOf('iphone') !== -1) {
+                agent = 'iphone';
+                touchscreen = true;
+            } else if (useragent.indexOf('ipad') !== -1) {
+                agent = 'ipad';
+                touchscreen = true;
+            } else if (useragent.indexOf('ipod') !== -1) {
+                agent = 'ipod';
+                touchscreen = true;
+            } else {
+                agent = 'normal';
+                touchscreen = false;
+            }
+            if (uri.query) {
+                server_set = (uri.query.server !== '');
+                server = uri.query.server || 'irc.anonnet.org';
+                nick = uri.query.nick || '';
+                debug = (uri.query.debug !== '');
+            } else {
+                server = 'irc.anonnet.org';
+                nick = '';
+            }
+            response.setHeader('Connection', 'close');
+            response.setHeader('X-Generated-By', 'KiwiIRC');
+            jade.renderFile(__dirname + '/client/index.html.jade', { locals: { "touchscreen": touchscreen, "debug": debug, "server_set": server_set, "server": server, "nick": nick, "agent": agent, "config": config }}, function (err, html) {
+                if (!err) {
+                    response.write(html);
+                } else {
+                    response.statusCode = 500;
+                }
+                response.end();
+            });
+        } else if (uri.pathname.substr(0, 10) === '/socket.io') {
+            return;
+        } else {
+            response.statusCode = 404;
+            response.end();
+        }
+    }
 };
 
 //setup websocket listener
 if (config.listen_ssl) {
-       var httpServer = https.createServer({key: fs.readFileSync(__dirname + '/' + config.ssl_key), cert: fs.readFileSync(__dirname + '/' + config.ssl_cert)}, httpHandler);
-       var io = ws.listen(httpServer, {secure: true});
-       httpServer.listen(config.port, config.bind_address);
+    var httpServer = https.createServer({key: fs.readFileSync(__dirname + '/' + config.ssl_key), cert: fs.readFileSync(__dirname + '/' + config.ssl_cert)}, httpHandler);
+    var io = ws.listen(httpServer, {secure: true});
+    httpServer.listen(config.port, config.bind_address);
 } else {
-       var httpServer = http.createServer(httpHandler);
-       var io = ws.listen(httpServer, {secure: false});
-       httpServer.listen(config.port, config.bind_address);
+    var httpServer = http.createServer(httpHandler);
+    var io = ws.listen(httpServer, {secure: false});
+    httpServer.listen(config.port, config.bind_address);
 }
 
 // Now we're listening on the network, set our UID/GIDs if required
@@ -495,105 +496,107 @@ changeUser();
 // The main socket listening/handling routines
 io.of('/kiwi').on('connection', function (websocket) {
 
-       websocket.sendClientEvent = function(event_name, data){
-               kiwi_mod.run(event_name, data, {websocket: this});
-               data.event = event_name;
-               this.emit('message', data);
-       };
-
-       websocket.sendServerLine = function(data, eol){
-               eol = (typeof eol === 'undefined') ? '\r\n' : eol;
-               this.ircSocket.write(data + eol);
-       }
-
-       websocket.on('irc connect', function (nick, host, port, ssl, callback) {
-               var ircSocket;
-               //setup IRC connection
-               if (!ssl) {
-                       ircSocket = net.createConnection(port, host);
-               } else {
-                       ircSocket = tls.connect(port, host);
-               }
-               ircSocket.setEncoding('ascii');
-               ircSocket.IRC = {options: {}, CAP: {negotiating: true, requested: [], enabled: []}};
-               websocket.ircSocket = ircSocket;
-               ircSocket.holdLast = false;
-               ircSocket.held = '';
-               
-               ircSocket.on('data', function (data) {
-                       ircSocketDataHandler(data, websocket, ircSocket);
-               });
-               
-               ircSocket.IRC.nick = nick;
-               // Send the login data
-               websocket.sendServerLine('CAP LS');
-               websocket.sendServerLine('NICK ' + nick);
-               websocket.sendServerLine('USER ' + nick + '_kiwi 0 0 :' + nick);
-
-               if ((callback) && (typeof (callback) === 'function')) {
-                       callback();
-               }
-       });
-       websocket.on('message', function (msg, callback) {
-               var args;
-               try {
-                       msg.data = JSON.parse(msg.data);
-                       args = msg.data.args;
-                       switch (msg.data.method) {
-                       case 'msg':
-                               if ((args.target) && (args.msg)) {
-                                       var obj = kiwi_mod.run('msgsend', args, {websocket: websocket});
-                                       if (obj !== null) websocket.sendServerLine('PRIVMSG ' + args.target + ' :' + args.msg);
-                               }
-                               break;
-                       case 'action':
-                               if ((args.target) && (args.msg)) {
-                                       websocket.sendServerLine('PRIVMSG ' + args.target + ' :\ 1ACTION ' + args.msg);
-                               }
-                               break;
-                       case 'raw':
-                               websocket.sendServerLine(args.data);
-                               break;
-                       case 'join':
-                               if (args.channel) {
-                                       _.each(args.channel.split(","), function (chan) {
-                                               websocket.sendServerLine('JOIN ' + chan);
-                                       });
-                               }
-                               break;
-                       case 'topic':
-                               if (args.channel) {
-                                       websocket.sendServerLine('TOPIC ' + args.channel + ' :' + args.topic);
-                               }
-                               break;
-                       case 'quit':
-                               websocket.ircSocket.end('QUIT :' + args.message + '\r\n');
-                               websocket.sentQUIT = true;
-                               websocket.ircSocket.destroySoon();
-                               websocket.disconnect();
-                               break;
-                       case 'notice':
-                               if ((args.target) && (args.msg)) {
-                                       websocket.sendServerLine('NOTICE ' + args.target + ' :' + args.msg);
-                               }
-                               break;
-                       default:
-                       }
-                       if ((callback) && (typeof (callback) === 'function')) {
-                               callback();
-                       }
-               } catch (e) {
-                       console.log("Caught error: " + e);
-               }
-       });
-
-       
-       websocket.on('disconnect', function () {
-               if ((!websocket.sentQUIT) && (websocket.ircSocket)) {
-                       websocket.ircSocket.end('QUIT :' + config.quit_message + '\r\n');
-                       websocket.sentQUIT = true;
-                       websocket.ircSocket.destroySoon();
-               }
-       });
+    websocket.sendClientEvent = function (event_name, data) {
+        kiwi_mod.run(event_name, data, {websocket: this});
+        data.event = event_name;
+        websocket.emit('message', data);
+    };
+
+    websocket.sendServerLine = function (data, eol) {
+        eol = (typeof eol === 'undefined') ? '\r\n' : eol;
+        websocket.ircSocket.write(data + eol);
+    };
+
+    websocket.on('irc connect', function (nick, host, port, ssl, callback) {
+        var ircSocket;
+        //setup IRC connection
+        if (!ssl) {
+            ircSocket = net.createConnection(port, host);
+        } else {
+            ircSocket = tls.connect(port, host);
+        }
+        ircSocket.setEncoding('ascii');
+        ircSocket.IRC = {options: {}, CAP: {negotiating: true, requested: [], enabled: []}};
+        websocket.ircSocket = ircSocket;
+        ircSocket.holdLast = false;
+        ircSocket.held = '';
+        
+        ircSocket.on('data', function (data) {
+            ircSocketDataHandler(data, websocket, ircSocket);
+        });
+        
+        ircSocket.IRC.nick = nick;
+        // Send the login data
+        websocket.sendServerLine('CAP LS');
+        websocket.sendServerLine('NICK ' + nick);
+        websocket.sendServerLine('USER ' + nick + '_kiwi 0 0 :' + nick);
+
+        if ((callback) && (typeof (callback) === 'function')) {
+            callback();
+        }
+    });
+    websocket.on('message', function (msg, callback) {
+        var args, obj;
+        try {
+            msg.data = JSON.parse(msg.data);
+            args = msg.data.args;
+            switch (msg.data.method) {
+            case 'msg':
+                if ((args.target) && (args.msg)) {
+                    obj = kiwi_mod.run('msgsend', args, {websocket: websocket});
+                    if (obj !== null) {
+                        websocket.sendServerLine('PRIVMSG ' + args.target + ' :' + args.msg);
+                    }
+                }
+                break;
+            case 'action':
+                if ((args.target) && (args.msg)) {
+                    websocket.sendServerLine('PRIVMSG ' + args.target + ' :\ 1ACTION ' + args.msg);
+                }
+                break;
+            case 'raw':
+                websocket.sendServerLine(args.data);
+                break;
+            case 'join':
+                if (args.channel) {
+                    _.each(args.channel.split(","), function (chan) {
+                        websocket.sendServerLine('JOIN ' + chan);
+                    });
+                }
+                break;
+            case 'topic':
+                if (args.channel) {
+                    websocket.sendServerLine('TOPIC ' + args.channel + ' :' + args.topic);
+                }
+                break;
+            case 'quit':
+                websocket.ircSocket.end('QUIT :' + args.message + '\r\n');
+                websocket.sentQUIT = true;
+                websocket.ircSocket.destroySoon();
+                websocket.disconnect();
+                break;
+            case 'notice':
+                if ((args.target) && (args.msg)) {
+                    websocket.sendServerLine('NOTICE ' + args.target + ' :' + args.msg);
+                }
+                break;
+            default:
+            }
+            if ((callback) && (typeof (callback) === 'function')) {
+                callback();
+            }
+        } catch (e) {
+            console.log("Caught error: " + e);
+        }
+    });
+
+    
+    websocket.on('disconnect', function () {
+        if ((!websocket.sentQUIT) && (websocket.ircSocket)) {
+            websocket.ircSocket.end('QUIT :' + config.quit_message + '\r\n');
+            websocket.sentQUIT = true;
+            websocket.ircSocket.destroySoon();
+        }
+    });
 });
 
index eaf508d2f3266e174620a8c8f4355d7788ef91ab..9f6911a0605f70e4c3bd16db06ac6ceb263258dc 100644 (file)
@@ -5,22 +5,22 @@
 
 var stats = {msgs: 0, topic_changes: 0};
 
-exports.onmsgsend = function(msg, opts){
-       stats.msgs++;
+exports.onmsgsend = function (msg, opts) {
+    stats.msgs++;
 
-       if(msg.msg === '!kiwistats'){
-               msg.msg = 'Messages sent: ' + stats.msgs.toString() + '. ';
-               msg.msg += 'Topics set: ' + stats.topic_changes.toString() + '. ';
+    if (msg.msg === '!kiwistats') {
+        msg.msg = 'Messages sent: ' + stats.msgs.toString() + '. ';
+        msg.msg += 'Topics set: ' + stats.topic_changes.toString() + '. ';
 
-               opts.websocket.sendClientEvent('msg', {nick: msg.target, ident: '', hostname: '', channel: msg.target, msg: msg.msg});
-               return null;
-       }
+        opts.websocket.sendClientEvent('msg', {nick: msg.target, ident: '', hostname: '', channel: msg.target, msg: msg.msg});
+        return null;
+    }
 
-       return msg;
+    return msg;
 }
 
-exports.ontopic = function(topic, opts){
-       stats.topic_changes++;
+exports.ontopic = function (topic, opts) {
+    stats.topic_changes++;
 
-       return topic;
-}
\ No newline at end of file
+    return topic;
+}
index c3db576ba7a42d98b4537c3b8aaabf932f4d6d15..54d79514636c8edf773a55c3ad9e5603e2595510 100644 (file)
@@ -1,3 +1,4 @@
+/*jslint node: true, sloppy: true, forin: true, maxerr: 50, indent: 4 */
 /*
  * Kiwi module handler
  *
 this.loaded_modules = {};
 
 
-exports.loadModules = function(){
-       // Warn each module it is about to be unloaded
-       this.run('unload');
-       this.loaded_modules = {};
+exports.loadModules = function (kiwi_root, config) {
+    var i, mod_name;
+    // Warn each module it is about to be unloaded
+    this.run('unload');
+    this.loaded_modules = {};
 
-       // Load each module and run the onload event
-       for(var i in config.modules){
-               var mod_name = config.modules[i];
-               this.loaded_modules[mod_name] = require(kiwi_root + '/' + config.module_dir + mod_name);
-       }
-       this.run('load');
-}
+    // Load each module and run the onload event
+    for (i in config.modules) {
+        mod_name = config.modules[i];
+        this.loaded_modules[mod_name] = require(kiwi_root + '/' + config.module_dir + mod_name);
+    }
+    this.run('load');
+};
 
-exports.run = function (event_name, event_data, opts){
-       var ret = event_data;
-       
-       event_data = (typeof event_data === 'undefined') ? {} : event_data;
-       opts = (typeof opts === 'undefined') ? {} : opts;
-       
-       for (var mod_name in this.loaded_modules) {
-               if (typeof this.loaded_modules[mod_name]['on' + event_name] === 'function') {
-                       ret = this.loaded_modules[mod_name]['on' + event_name](ret, opts);
-                       if (ret === null) return null;
-               }
-       }
+exports.run = function (event_name, event_data, opts) {
+    var ret = event_data,
+        mod_name;
+    
+    event_data = (typeof event_data === 'undefined') ? {} : event_data;
+    opts = (typeof opts === 'undefined') ? {} : opts;
+    
+    for (mod_name in this.loaded_modules) {
+        if (typeof this.loaded_modules[mod_name]['on' + event_name] === 'function') {
+            ret = this.loaded_modules[mod_name]['on' + event_name](ret, opts);
+            if (ret === null) {
+                return null;
+            }
+        }
+    }
 
-       return ret;
-}
+    return ret;
+};
 
-exports.printMods = function(){
-       console.log('Loaded Kiwi modules');
-       for (var mod_name in this.loaded_modules) {
-               console.log(' - ' + mod_name);
-       }
-}
\ No newline at end of file
+exports.printMods = function () {
+    var mod_name;
+    console.log('Loaded Kiwi modules');
+    for (mod_name in this.loaded_modules) {
+        console.log(' - ' + mod_name);
+    }
+};