From a3364605d47fce5a4fe6d7133c776cf04275417c Mon Sep 17 00:00:00 2001 From: Jack Allnutt Date: Sun, 31 Jul 2011 10:01:24 +0100 Subject: [PATCH] General tidying up! Front.js now (almost) passes jslint, although it still uses eval() and possibly leaks global variables. Fix for new message sending. --- js/front.js | 2300 ++++++++++++++++--------------- js/gateway.js | 244 ++-- node/kiwi.js | 1075 ++++++++------- node/kiwi_modules/statistics.js | 26 +- node/lib/kiwi_mod.js | 68 +- 5 files changed, 1891 insertions(+), 1822 deletions(-) diff --git a/js/front.js b/js/front.js index d09087d..223422b 100644 --- a/js/front.js +++ b/js/front.js @@ -1,112 +1,118 @@ +/*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; - $('
  • ' + mode + nick + '
  • ').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; + $('
  • ' + mode + nick + '
  • ').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;'); - $('
  • ' + data.nick + '
  • ').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;'); + $('
  • ' + data.nick + '
  • ').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(''); - } - - // 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(''); + } + + // 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('
    '); - $('#kiwi .userlist').append(''); - $('#kiwi .windowlist ul').append('
  • ' + v_name + '
  • '); - } - //$('#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 = '
    \ - \ - Message\ - Info\ + }); + 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('
    '); + $('#kiwi .userlist').append(''); + $('#kiwi .windowlist ul').append('
  • ' + v_name + '
  • '); + } + //$('#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 = '
    \ + \ + Message\ + Info\
    '; - 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 = ''; - 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 = $('
    ').text('<'+nick+'>').html(); - //} else { - var html_nick = $('
    ').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 = $('
    ').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 = ''; - while(msg.indexOf(String.fromCharCode(2)) != -1){ - msg = msg.replace(String.fromCharCode(2), next); - next = (next=='') ? '' : ''; - } - if(next == '') msg =+ ''; - } - - // Wierd thing noticed by Dux0r on the irc.esper.net server - if(typeof msg != "string") msg = ''; - - // underline - if(msg.indexOf(String.fromCharCode(31))){ - next = ''; - while(msg.indexOf(String.fromCharCode(31)) != -1){ - msg = msg.replace(String.fromCharCode(31), next); - next = (next=='') ? '' : ''; - } - if(next == '') msg =+ ''; - } - - 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 = ''; + 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 = $('
    ').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 = $('
    ').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 = ''; + while (msg.indexOf(String.fromCharCode(2)) !== -1) { + msg = msg.replace(String.fromCharCode(2), next); + next = (next === '') ? '' : ''; + } + if (next === '') { + msg = msg + ''; + } + } + + // 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 = ''; + while (msg.indexOf(String.fromCharCode(31)) !== -1) { + msg = msg.replace(String.fromCharCode(31), next); + next = (next === '') ? '' : ''; + } + if (next === '') { + msg = msg + ''; + } + } + + re = new RegExp('\\B(' + gateway.channel_prefix + '[^ ,.\\007]+)', 'g'); + + msg = msg.replace(re, function (match) { return '' + match + ''; }); - var line_msg = $('
    '+time+'
    '+html_nick+'
    '+msg+'
    '); - 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 = $('
    '); - $('#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 = $('
    ' + time + '
    ' + html_nick + '
    ' + msg + '
    '); + 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 = $('
    '); + $('#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(); +}; diff --git a/js/gateway.js b/js/gateway.js index d7fda90..0ff36cd 100644 --- a/js/gateway.js +++ b/js/gateway.js @@ -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); } diff --git a/node/kiwi.js b/node/kiwi.js index 3dc0e65..3411196 100644 --- a/node/kiwi.js +++ b/node/kiwi.js @@ -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 + ' :ACTION ' + 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 + ' :ACTION ' + 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(); + } + }); }); diff --git a/node/kiwi_modules/statistics.js b/node/kiwi_modules/statistics.js index eaf508d..9f6911a 100644 --- a/node/kiwi_modules/statistics.js +++ b/node/kiwi_modules/statistics.js @@ -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; +} diff --git a/node/lib/kiwi_mod.js b/node/lib/kiwi_mod.js index c3db576..54d7951 100644 --- a/node/lib/kiwi_mod.js +++ b/node/lib/kiwi_mod.js @@ -1,3 +1,4 @@ +/*jslint node: true, sloppy: true, forin: true, maxerr: 50, indent: 4 */ /* * Kiwi module handler * @@ -14,38 +15,43 @@ 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); + } +}; -- 2.25.1