-var _ = require('underscore');
-
-var irc_numerics = {
- RPL_WELCOME: '001',
- RPL_MYINFO: '004',
- RPL_ISUPPORT: '005',
- RPL_WHOISREGNICK: '307',
- RPL_WHOISUSER: '311',
- RPL_WHOISSERVER: '312',
- RPL_WHOISOPERATOR: '313',
- RPL_WHOISIDLE: '317',
- RPL_ENDOFWHOIS: '318',
- RPL_WHOISCHANNELS: '319',
- RPL_LISTSTART: '321',
- RPL_LIST: '322',
- RPL_LISTEND: '323',
- RPL_NOTOPIC: '331',
- RPL_TOPIC: '332',
- RPL_TOPICWHOTIME: '333',
- RPL_NAMEREPLY: '353',
- RPL_ENDOFNAMES: '366',
- RPL_BANLIST: '367',
- RPL_ENDOFBANLIST: '368',
- RPL_MOTD: '372',
- RPL_MOTDSTART: '375',
- RPL_ENDOFMOTD: '376',
- RPL_WHOISMODES: '379',
- ERR_NOSUCHNICK: '401',
- ERR_CANNOTSENDTOCHAN: '404',
- ERR_TOOMANYCHANNELS: '405',
- ERR_NICKNAMEINUSE: '433',
- ERR_USERNOTINCHANNEL: '441',
- ERR_NOTONCHANNEL: '442',
- ERR_NOTREGISTERED: '451',
- ERR_LINKCHANNEL: '470',
- ERR_CHANNELISFULL: '471',
- ERR_INVITEONLYCHAN: '473',
- ERR_BANNEDFROMCHAN: '474',
- ERR_BADCHANNELKEY: '475',
- ERR_CHANOPRIVSNEEDED: '482',
- RPL_STARTTLS: '670'
+var _ = require('lodash'),
+ irc_numerics,
+ IrcCommands,
+ handlers,
+ unknownCommand;
+
+irc_numerics = {
+ '001': 'RPL_WELCOME',
+ '004': 'RPL_MYINFO',
+ '005': 'RPL_ISUPPORT',
+ '006': 'RPL_MAPMORE',
+ '007': 'RPL_MAPEND',
+ '250': 'RPL_STATSCONN',
+ '251': 'RPL_LUSERCLIENT',
+ '252': 'RPL_LUSEROP',
+ '253': 'RPL_LUSERUNKNOWN',
+ '254': 'RPL_LUSERCHANNELS',
+ '255': 'RPL_LUSERME',
+ '265': 'RPL_LOCALUSERS',
+ '266': 'RPL_GLOBALUSERS',
+ '301': 'RPL_AWAY',
+ '307': 'RPL_WHOISREGNICK',
+ '311': 'RPL_WHOISUSER',
+ '312': 'RPL_WHOISSERVER',
+ '313': 'RPL_WHOISOPERATOR',
+ '314': 'RPL_WHOWASUSER',
+ '315': 'RPL_ENDOFWHO',
+ '317': 'RPL_WHOISIDLE',
+ '318': 'RPL_ENDOFWHOIS',
+ '319': 'RPL_WHOISCHANNELS',
+ '321': 'RPL_LISTSTART',
+ '322': 'RPL_LIST',
+ '323': 'RPL_LISTEND',
+ '324': 'RPL_CHANNELMODEIS',
+ '328': 'RPL_CHANNEL_URL',
+ '329': 'RPL_CREATIONTIME',
+ '330': 'RPL_WHOISACCOUNT',
+ '331': 'RPL_NOTOPIC',
+ '332': 'RPL_TOPIC',
+ '333': 'RPL_TOPICWHOTIME',
+ '341': 'RPL_INVITING',
+ '352': 'RPL_WHOREPLY',
+ '353': 'RPL_NAMEREPLY',
+ '364': 'RPL_LINKS',
+ '365': 'RPL_ENDOFLINKS',
+ '366': 'RPL_ENDOFNAMES',
+ '367': 'RPL_BANLIST',
+ '368': 'RPL_ENDOFBANLIST',
+ '369': 'RPL_ENDOFWHOWAS',
+ '372': 'RPL_MOTD',
+ '375': 'RPL_MOTDSTART',
+ '376': 'RPL_ENDOFMOTD',
+ '378': 'RPL_WHOISHOST',
+ '379': 'RPL_WHOISMODES',
+ '401': 'ERR_NOSUCHNICK',
+ '404': 'ERR_CANNOTSENDTOCHAN',
+ '405': 'ERR_TOOMANYCHANNELS',
+ '406': 'ERR_WASNOSUCHNICK',
+ '421': 'ERR_UNKNOWNCOMMAND',
+ '422': 'ERR_NOMOTD',
+ '432': 'ERR_ERRONEUSNICKNAME',
+ '433': 'ERR_NICKNAMEINUSE',
+ '441': 'ERR_USERNOTINCHANNEL',
+ '442': 'ERR_NOTONCHANNEL',
+ '443': 'ERR_USERONCHANNEL',
+ '451': 'ERR_NOTREGISTERED',
+ '464': 'ERR_PASSWDMISMATCH',
+ '470': 'ERR_LINKCHANNEL',
+ '471': 'ERR_CHANNELISFULL',
+ '473': 'ERR_INVITEONLYCHAN',
+ '474': 'ERR_BANNEDFROMCHAN',
+ '475': 'ERR_BADCHANNELKEY',
+ '481': 'ERR_NOPRIVILEGES',
+ '482': 'ERR_CHANOPRIVSNEEDED',
+ '670': 'RPL_STARTTLS',
+ '671': 'RPL_WHOISSECURE',
+ '900': 'RPL_SASLAUTHENTICATED',
+ '903': 'RPL_SASLLOGGEDIN',
+ '904': 'ERR_SASLNOTAUTHORISED',
+ '906': 'ERR_SASLABORTED',
+ '907': 'ERR_SASLALREADYAUTHED'
};
-var IrcCommands = function (irc_connection, con_num, client) {
+IrcCommands = function (irc_connection) {
this.irc_connection = irc_connection;
- this.con_num = con_num;
- this.client = client;
};
module.exports = IrcCommands;
-IrcCommands.prototype.bindEvents = function () {
- var that = this;
+IrcCommands.prototype.dispatch = function (command, data) {
+ command += '';
+ if (irc_numerics[command]) {
+ command = irc_numerics[command];
+ }
+ if (handlers[command]) {
+ handlers[command].call(this, data);
+ } else {
+ unknownCommand.call(this, command, data);
+ }
+};
- _.each(listeners, function (listener, command) {
- var s = command.substr(0, 4);
- if ((s === 'RPL_') || (s === 'ERR_')) {
- command = irc_numerics[command];
- }
- that.irc_connection.on('irc_' + command, function () {
- listener.apply(that, arguments);
- });
- });
+IrcCommands.addHandler = function (command, handler) {
+ if (typeof handler !== 'function') {
+ return false;
+ }
+ handlers[command] = handler;
};
-IrcCommands.prototype.dispose = function () {
- this.removeAllListeners();
+IrcCommands.addNumeric = function (numeric, handler_name) {
+ irc_numerics[numeric + ''] = handler_name +'';
};
+unknownCommand = function (command, data) {
+ var params = _.clone(data.params);
+
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' unknown_command', {
+ command: command,
+ params: params,
+ trailing: data.trailing
+ });
+
+/*
+ this.irc_connection.emit(namespace + ' ' + command.params[0] + ' notice', {
+ from_server: command.prefix ? true : false,
+ nick: command.nick || command.prefix || undefined,
+ ident: command.ident,
+ hostname: command.hostname,
+ target: command.params[0],
+ msg: command.trailing
+ });
+ */
+ };
-var listeners = {
- 'RPL_WELCOME': function (command) {
- var nick = command.params[0];
- this.irc_connection.registered = true;
- this.client.sendIrcCommand('connect', {server: this.con_num, nick: nick});
- },
- 'RPL_ISUPPORT': function (command) {
- var options, i, option, matches, j;
- options = command.params;
- for (i = 1; i < options.length; i++) {
- option = options[i].split("=", 2);
- option[0] = option[0].toUpperCase();
- this.irc_connection.options[option[0]] = (typeof option[1] !== 'undefined') ? option[1] : true;
- if (_.include(['NETWORK', 'PREFIX', 'CHANTYPES', 'CHANMODES', 'NAMESX'], option[0])) {
- if (option[0] === 'PREFIX') {
- matches = /\(([^)]*)\)(.*)/.exec(option[1]);
- if ((matches) && (matches.length === 3)) {
- this.irc_connection.options.PREFIX = [];
- for (j = 0; j < matches[2].length; j++) {
- this.irc_connection.options.PREFIX.push({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
- }
- }
- } else if (option[0] === 'CHANTYPES') {
- this.irc_connection.options.CHANTYPES = this.irc_connection.options.CHANTYPES.split('');
- } else if (option[0] === 'CHANMODES') {
- this.irc_connection.options.CHANMODES = option[1].split(',');
- } else if (option[0] === 'NAMESX') {
- this.irc_connection.write('PROTOCTL NAMESX');
+
+handlers = {
+ 'RPL_WELCOME': function (command) {
+ var nick = command.params[0];
+ this.irc_connection.registered = true;
+ this.cap_negotation = false;
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' connect', {
+ nick: nick
+ });
+ },
+
+ 'RPL_ISUPPORT': function (command) {
+ var options, i, option, matches, j;
+ options = command.params;
+ for (i = 1; i < options.length; i++) {
+ option = options[i].split("=", 2);
+ option[0] = option[0].toUpperCase();
+ this.irc_connection.options[option[0]] = (typeof option[1] !== 'undefined') ? option[1] : true;
+ if (_.include(['NETWORK', 'PREFIX', 'CHANTYPES', 'CHANMODES', 'NAMESX'], option[0])) {
+ if (option[0] === 'PREFIX') {
+ matches = /\(([^)]*)\)(.*)/.exec(option[1]);
+ if ((matches) && (matches.length === 3)) {
+ this.irc_connection.options.PREFIX = [];
+ for (j = 0; j < matches[2].length; j++) {
+ this.irc_connection.options.PREFIX.push({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
}
}
+ } else if (option[0] === 'CHANTYPES') {
+ this.irc_connection.options.CHANTYPES = this.irc_connection.options.CHANTYPES.split('');
+ } else if (option[0] === 'CHANMODES') {
+ this.irc_connection.options.CHANMODES = option[1].split(',');
+ } else if ((option[0] === 'NAMESX') && (!_.contains(this.irc_connection.cap.enabled, 'multi-prefix'))) {
+ this.irc_connection.write('PROTOCTL NAMESX');
}
- //this.client.sendIrcCommand({server: this.con_num, command: 'RPL_ISUPPORT', options: this.irc_connection.options});
- //websocket.sendClientEvent('options', {server: '', "options": irc_connection.IRC.options});
- this.client.sendIrcCommand('options', {server: this.con_num, options: this.irc_connection.options});
- },
- 'RPL_ENDOFWHOIS': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_ENDOFWHOIS';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: true});
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: true});
- },
- 'RPL_WHOISUSER': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_WHOISUSER';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], ident: command.params[2], host: command.params[3], msg: command.trailing, end: false});
- },
- 'RPL_WHOISSERVER': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_WHOISSERVER';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], irc_server: command.params[2], end: false});
- },
- 'RPL_WHOISOPERATOR': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_WHOISOPERATOR';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
- },
- 'RPL_WHOISCHANNELS': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_WHOISCHANNELS';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], chans: command.trailing, end: false});
- },
- 'RPL_WHOISMODES': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_WHOISMODES';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
- },
- 'RPL_WHOISIDLE': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_WHOISIDLE';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('whois', {server: '', nick: msg.params.split(" ", 3)[1], "msg": msg.trailing, end: false});
- if (command.params[3]) {
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], logon: command.params[3], end: false});
- } else {
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], end: false});
- }
- },
- 'RPL_WHOISREGNICK': function (command) {
- this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false});
- },
- 'RPL_LISTSTART': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_LISTSTART';
- this.client.sendIrcCommand(command);*/
- this.client.sendIrcCommand('list_start', {server: this.con_num});
- this.client.buffer.list = [];
- },
- 'RPL_LISTEND': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_LISTEND';
- this.client.sendIrcCommand(command);*/
- if (this.client.buffer.list.length > 0) {
- this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) {
- return channel.num_users;
- });
- this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list});
- this.client.buffer.list = [];
- }
- this.client.sendIrcCommand('list_end', {server: this.con_num});
- },
- 'RPL_LIST': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_LIST';
- this.client.sendIrcCommand(command);*/
- this.client.buffer.list.push({server: this.con_num, channel: command.params[1], num_users: parseInt(command.params[2], 10), topic: command.trailing});
- if (this.client.buffer.list.length > 200){
- this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) {
- return channel.num_users;
- });
- this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list});
- this.client.buffer.list = [];
- }
- },
- 'RPL_MOTD': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_MOTD';
- this.client.sendIrcCommand(command);*/
- this.client.buffer.motd += command.trailing + '\n';
- },
- 'RPL_MOTDSTART': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_MOTDSTART';
- this.client.sendIrcCommand(command);*/
- this.client.buffer.motd = '';
- },
- 'RPL_ENDOFMOTD': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_ENDOFMOTD';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('motd', {server: '', 'msg': websocket.kiwi.buffer.motd});
- this.client.sendIrcCommand('motd', {server: this.con_num, msg: this.client.buffer.motd});
- },
- 'RPL_NAMEREPLY': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_NAMEREPLY';
- this.client.sendIrcCommand(command);*/
- var members = command.trailing.split(' ');
- var member_list = [];
- var that = this;
- var i = 0;
- _.each(members, function (member) {
- var j, k, modes = [];
- for (j = 0; j < member.length; j++) {
- for (k = 0; k < that.irc_connection.options.PREFIX.length; k++) {
- if (member.charAt(j) === that.irc_connection.options.PREFIX[k].symbol) {
- modes.push(that.irc_connection.options.PREFIX[k].mode);
- i++;
- }
- }
- }
- member_list.push({nick: member, modes: modes});
- if (i++ >= 50) {
- that.client.sendIrcCommand('userlist', {server: that.con_num, users: member_list, channel: command.params[2]});
- member_list = [];
- i = 0;
+ }
+ }
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' options', {
+ options: this.irc_connection.options,
+ cap: this.irc_connection.cap.enabled
+ });
+ },
+
+ 'RPL_ENDOFWHOIS': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' endofwhois', {
+ nick: command.params[1],
+ msg: command.trailing
+ });
+ },
+
+ 'RPL_AWAY': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoisaway', {
+ nick: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ 'RPL_WHOISUSER': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoisuser', {
+ nick: command.params[1],
+ ident: command.params[2],
+ host: command.params[3],
+ msg: command.trailing
+ });
+ },
+
+ 'RPL_WHOISSERVER': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoisserver', {
+ nick: command.params[1],
+ irc_server: command.params[2],
+ server_info: command.trailing
+ });
+ },
+
+ 'RPL_WHOISOPERATOR': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoisoperator', {
+ nick: command.params[1],
+ msg: command.trailing
+ });
+ },
+
+ 'RPL_WHOISCHANNELS': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoischannels', {
+ nick: command.params[1],
+ chans: command.trailing
+ });
+ },
+
+ 'RPL_WHOISMODES': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoismodes', {
+ nick: command.params[1],
+ msg: command.trailing
+ });
+ },
+
+ 'RPL_WHOISIDLE': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoisidle', {
+ nick: command.params[1],
+ idle: command.params[2],
+ logon: command.params[3] || undefined
+ });
+ },
+
+ 'RPL_WHOISREGNICK': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoisregnick', {
+ nick: command.params[1],
+ msg: command.trailing
+ });
+ },
+
+ 'RPL_WHOISHOST': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoishost', {
+ nick: command.params[1],
+ msg: command.trailing
+ });
+ },
+
+ 'RPL_WHOISSECURE': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoissecure', {
+ nick: command.params[1]
+ });
+ },
+
+ 'RPL_WHOISACCOUNT': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whoisaccount', {
+ nick: command.params[1],
+ account: command.params[2]
+ });
+ },
+
+ 'RPL_WHOWASUSER': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' whowas', {
+ nick: command.params[1],
+ ident: command.params[2],
+ host: command.params[3],
+ real_name: command.trailing
+ });
+ },
+
+ 'RPL_ENDOFWHOWAS': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' endofwhowas', {
+ nick: command.params[1]
+ });
+ },
+
+ 'ERR_WASNOSUCHNICK': function (command) {
+ this.irc_connection.emit('user ' + command.params[1] + ' wasnosucknick', {
+ nick: command.params[1]
+ });
+ },
+
+ 'RPL_LISTSTART': function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_start', {});
+ },
+
+ 'RPL_LISTEND': function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_end', {});
+ },
+
+ 'RPL_LIST': function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_channel', {
+ channel: command.params[1],
+ num_users: parseInt(command.params[2], 10),
+ topic: command.trailing
+ });
+ },
+
+ 'RPL_CHANNELMODEIS': function (command) {
+ var channel = command.params[1],
+ modes = parseModeList.call(this, command.params[2], command.params.slice(3));
+
+ this.irc_connection.emit('channel ' + channel + ' info', {
+ channel: channel,
+ modes: modes
+ });
+ },
+
+ 'RPL_CREATIONTIME': function (command) {
+ var channel = command.params[1];
+
+ this.irc_connection.emit('channel ' + channel + ' info', {
+ channel: channel,
+ created_at: parseInt(command.params[2], 10)
+ });
+ },
+
+ 'RPL_CHANNEL_URL': function (command) {
+ var channel = command.params[1];
+
+ this.irc_connection.emit('channel ' + channel + ' info', {
+ channel: channel,
+ url: command.trailing
+ });
+ },
+
+ 'RPL_MOTD': function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' motd', {
+ motd: command.trailing + '\n'
+ });
+ },
+
+ 'RPL_MOTDSTART': function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' motd_start', {});
+ },
+
+ 'RPL_ENDOFMOTD': function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' motd_end', {});
+ },
+
+ 'RPL_NAMEREPLY': function (command) {
+ var members = command.trailing.split(' ');
+ var member_list = [];
+ var that = this;
+ _.each(members, function (member) {
+ var i = 0,
+ j = 0,
+ modes = [];
+
+ // Make sure we have some prefixes already
+ if (that.irc_connection.options.PREFIX) {
+ for (j = 0; j < that.irc_connection.options.PREFIX.length; j++) {
+ if (member.charAt(i) === that.irc_connection.options.PREFIX[j].symbol) {
+ modes.push(that.irc_connection.options.PREFIX[j].mode);
+ i++;
}
- });
- if (i > 0) {
- this.client.sendIrcCommand('userlist', {server: this.con_num, users: member_list, channel: command.params[2]});
}
- },
- 'RPL_ENDOFNAMES': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_ENDOFNAMES';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('userlist_end', {server: '', channel: msg.params.split(" ")[1]});
- this.client.sendIrcCommand('userlist_end', {server: this.con_num, channel: command.params[1]});
- },
- 'RPL_BANLIST': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_BANLIST';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('banlist', {server: '', channel: params[1], banned: params[2], banned_by: params[3], banned_at: params[4]});
- this.client.sendIrcCommand('banlist', {server: this.con_num, channel: command.params[1], banned: command.params[2], banned_by: command.params[3], banned_at: command.params[4]});
- },
- 'RPL_ENDOFBANLIST': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_ENDOFBANLIST';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('banlist_end', {server: '', channel: msg.params.split(" ")[1]});
- this.client.sendIrcCommand('banlist_end', {server: this.con_num, channel: command.params[1]});
- },
- 'RPL_TOPIC': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_TOPIC';
- this.client.sendIrcCommand(command);*/
- //{nick: '', channel: msg.params.split(" ")[1], topic: msg.trailing};
- this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: command.trailing});
- },
- 'RPL_NOTOPIC': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_NOTOPIC';
- this.client.sendIrcCommand(command);*/
- this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: ''});
- },
- 'RPL_TOPICWHOTIME': function (command) {
- /*command.server = this.con_num;
- command.command = 'RPL_TOPICWHOTIME';
- this.client.sendIrcCommand(command);*/
- //{nick: nick, channel: channel, when: when};
- this.client.sendIrcCommand('topicsetby', {server: this.con_num, nick: command.params[2], channel: command.params[1], when: command.params[3]});
- },
- 'PING': function (command) {
- this.irc_connection.write('PONG ' + command.trailing);
- },
- 'JOIN': function (command) {
- var channel;
- if (typeof command.trailing === 'string' && command.trailing !== '') {
- channel = command.trailing;
- } else if (typeof command.params[0] === 'string' && command.params[0] !== '') {
- channel = command.params[0];
- }
- /*command.server = this.con_num;
- command.command = 'JOIN';
- command.params = [channel];
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('join', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: channel});
- this.client.sendIrcCommand('join', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: channel});
-
- if (command.nick === this.nick) {
- this.irc_connection.write('NAMES ' + channel);
- }
- },
- 'PART': function (command) {
- /*command.server = this.con_num;
- command.command = 'PART';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('part', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), message: msg.trailing});
- this.client.sendIrcCommand('part', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], message: command.trailing});
- },
- 'KICK': function (command) {
- /*command.server = this.con_num;
- command.command = 'KICK';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('kick', {kicked: params[1], nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: params[0].trim(), message: msg.trailing});
- this.client.sendIrcCommand('kick', {server: this.con_num, kicked: command.params[1], nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], message: command.trailing});
- },
- 'QUIT': function (command) {
- /*command.server = this.con_num;
- command.command = 'QUIT';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('quit', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, message: msg.trailing});
- this.client.sendIrcCommand('quit', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, message: command.trailing});
- },
- 'NOTICE': function (command) {
- /*command.server = this.con_num;
- command.command = 'NOTICE';
- this.client.sendIrcCommand(command);*/
- if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.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)});
- this.client.sendIrcCommand('ctcp_response', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(1, command.trailing.length - 2)});
+ }
+
+ member_list.push({nick: member, modes: modes});
+ });
+
+ this.irc_connection.emit('channel ' + command.params[2] + ' userlist', {
+ users: member_list,
+ channel: command.params[2]
+ });
+ },
+
+ 'RPL_ENDOFNAMES': function (command) {
+ this.irc_connection.emit('channel ' + command.params[1] + ' userlist_end', {
+ channel: command.params[1]
+ });
+ },
+
+ 'RPL_WHOREPLY': function (command) {
+ // For the time being, NOOP this command so they don't get passed
+ // down to the client. Waste of bandwidth since we do not use it yet
+ // TODO: Impliment RPL_WHOREPLY
+ },
+
+ 'RPL_ENDOFWHO': function (command) {
+ // For the time being, NOOP this command so they don't get passed
+ // down to the client. Waste of bandwidth since we do not use it yet
+ // TODO: Impliment RPL_ENDOFWHO
+ },
+
+ 'RPL_BANLIST': function (command) {
+ this.irc_connection.emit('channel ' + command.params[1] + ' banlist', {
+ channel: command.params[1],
+ banned: command.params[2],
+ banned_by: command.params[3],
+ banned_at: command.params[4]
+ });
+ },
+
+ 'RPL_ENDOFBANLIST': function (command) {
+ this.irc_connection.emit('channel ' + command.params[1] + ' banlist_end', {
+ channel: command.params[1]
+ });
+ },
+
+ 'RPL_TOPIC': function (command) {
+ this.irc_connection.emit('channel ' + command.params[1] + ' topic', {
+ channel: command.params[1],
+ topic: command.trailing
+ });
+ },
+
+ 'RPL_NOTOPIC': function (command) {
+ this.irc_connection.emit('channel ' + command.params[1] + ' topic', {
+ channel: command.params[1],
+ topic: ''
+ });
+ },
+
+ 'RPL_TOPICWHOTIME': function (command) {
+ this.irc_connection.emit('channel ' + command.params[1] + ' topicsetby', {
+ nick: command.params[2],
+ channel: command.params[1],
+ when: command.params[3]
+ });
+ },
+
+ 'RPL_INVITING': function (command) {
+ this.irc_connection.emit('channel ' + command.params[1] + ' invited', {
+ nick: command.params[0],
+ channel: command.params[1]
+ });
+ },
+
+ 'PING': function (command) {
+ this.irc_connection.write('PONG ' + command.trailing);
+ },
+
+ 'JOIN': function (command) {
+ var channel, time;
+ if (typeof command.trailing === 'string' && command.trailing !== '') {
+ channel = command.trailing;
+ } else if (typeof command.params[0] === 'string' && command.params[0] !== '') {
+ channel = command.params[0];
+ }
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ this.irc_connection.emit('channel ' + channel + ' join', {
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ channel: channel,
+ time: time
+ });
+ },
+
+ 'PART': function (command) {
+ var time;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ this.irc_connection.emit('channel ' + command.params[0] + ' part', {
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ channel: command.params[0],
+ message: command.trailing,
+ time: time
+ });
+ },
+
+ 'KICK': function (command) {
+ var time;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ this.irc_connection.emit('channel ' + command.params[0] + ' kick', {
+ kicked: command.params[1],
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ channel: command.params[0],
+ message: command.trailing,
+ time: time
+ });
+ },
+
+ 'QUIT': function (command) {
+ var time;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ this.irc_connection.emit('user ' + command.nick + ' quit', {
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ message: command.trailing,
+ time: time
+ });
+ },
+
+ 'NOTICE': function (command) {
+ var namespace,
+ time;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+
+ if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
+ // It's a CTCP response
+ namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase()) ? 'user' : 'channel';
+ this.irc_connection.emit(namespace + ' ' + command.params[0] + ' ctcp_response', {
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ channel: command.params[0],
+ msg: command.trailing.substring(1, command.trailing.length - 1),
+ time: time
+ });
+ } else {
+ namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase() || command.params[0] == '*') ?
+ 'user' :
+ 'channel';
+
+ this.irc_connection.emit(namespace + ' ' + command.params[0] + ' notice', {
+ from_server: command.prefix ? true : false,
+ nick: command.nick || command.prefix || undefined,
+ ident: command.ident,
+ hostname: command.hostname,
+ target: command.params[0],
+ msg: command.trailing,
+ time: time
+ });
+ }
+ },
+
+ 'NICK': function (command) {
+ var time;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ this.irc_connection.emit('user ' + command.nick + ' nick', {
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ newnick: command.trailing || command.params[0],
+ time: time
+ });
+ },
+
+ 'TOPIC': function (command) {
+ var time;
+
+ // If we don't have an associated channel, no need to continue
+ if (!command.params[0]) return;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ var channel = command.params[0],
+ topic = command.trailing || '';
+
+ this.irc_connection.emit('channel ' + channel + ' topic', {
+ nick: command.nick,
+ channel: channel,
+ topic: topic,
+ time: time
+ });
+ },
+
+ 'MODE': function (command) {
+ var modes = [], event, time;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ // Get a JSON representation of the modes
+ modes = parseModeList.call(this, command.params[1] || command.trailing, command.params.slice(2));
+ event = (_.contains(this.irc_connection.options.CHANTYPES, command.params[0][0]) ? 'channel ' : 'user ') + command.params[0] + ' mode';
+
+ this.irc_connection.emit(event, {
+ target: command.params[0],
+ nick: command.nick || command.prefix || '',
+ modes: modes,
+ time: time
+ });
+ },
+
+ 'PRIVMSG': function (command) {
+ var tmp, namespace, time;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
+ //CTCP request
+ if (command.trailing.substr(1, 6) === 'ACTION') {
+ this.irc_connection.clientEvent('action', {
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ channel: command.params[0],
+ msg: command.trailing.substring(8, command.trailing.length - 1),
+ time: time
+ });
+ } else if (command.trailing.substr(1, 4) === 'KIWI') {
+ tmp = command.trailing.substring(6, command.trailing.length - 1);
+ namespace = tmp.split(' ', 1)[0];
+ this.irc_connection.clientEvent('kiwi', {
+ namespace: namespace,
+ data: tmp.substr(namespace.length + 1),
+ time: time
+ });
+ } else if (command.trailing.substr(1, 7) === 'VERSION') {
+ this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'VERSION KiwiIRC' + String.fromCharCode(1));
+ } else if (command.trailing.substr(1, 6) === 'SOURCE') {
+ this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'SOURCE http://www.kiwiirc.com/' + String.fromCharCode(1));
+ } else if (command.trailing.substr(1, 10) === 'CLIENTINFO') {
+ this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'CLIENTINFO SOURCE VERSION TIME' + String.fromCharCode(1));
+ } else {
+ namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase()) ? 'user' : 'channel';
+ this.irc_connection.emit(namespace + ' ' + command.nick + ' ctcp_request', {
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ target: command.params[0],
+ type: (command.trailing.substring(1, command.trailing.length - 1).split(' ') || [null])[0],
+ msg: command.trailing.substring(1, command.trailing.length - 1),
+ time: time
+ });
+ }
+ } else {
+ // A message to a user (private message) or to a channel?
+ namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase()) ? 'user ' + command.nick : 'channel ' + command.params[0];
+ this.irc_connection.emit(namespace + ' privmsg', {
+ nick: command.nick,
+ ident: command.ident,
+ hostname: command.hostname,
+ channel: command.params[0],
+ msg: command.trailing,
+ time: time
+ });
+ }
+ },
+
+ 'CAP': function (command) {
+ // TODO: capability modifiers
+ // i.e. - for disable, ~ for requires ACK, = for sticky
+ var capabilities = command.trailing.replace(/(?:^| )[\-~=]/, '').split(' ');
+ var request;
+
+ // Which capabilities we want to enable
+ var want = ['multi-prefix', 'away-notify', 'server-time', 'znc.in/server-time-iso', 'znc.in/server-time'];
+
+ if (this.irc_connection.password) {
+ want.push('sasl');
+ }
+
+ switch (command.params[1]) {
+ case 'LS':
+ // Compute which of the available capabilities we want and request them
+ request = _.intersection(capabilities, want);
+ if (request.length > 0) {
+ this.irc_connection.cap.requested = request;
+ this.irc_connection.write('CAP REQ :' + request.join(' '));
} else {
- //websocket.sendClientEvent('notice', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, target: msg.params.trim(), msg: msg.trailing});
- this.client.sendIrcCommand('notice', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, target: command.params[0], msg: command.trailing});
+ this.irc_connection.write('CAP END');
+ this.irc_connection.cap_negotation = false;
+ }
+ break;
+ case 'ACK':
+ if (capabilities.length > 0) {
+ // Update list of enabled capabilities
+ this.irc_connection.cap.enabled = capabilities;
+ // Update list of capabilities we would like to have but that aren't enabled
+ this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
}
- },
- 'NICK': function (command) {
- /*command.server = this.con_num;
- command.command = 'NICK';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('nick', {nick: msg.nick, ident: msg.ident, hostname: msg.hostname, newnick: msg.trailing});
- this.client.sendIrcCommand('nick', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, newnick: command.trailing});
- },
- 'TOPIC': function (command) {
- /*command.server = this.con_num;
- command.command = 'TOPIC';
- this.client.sendIrcCommand(command);*/
- //{nick: msg.nick, channel: msg.params, topic: msg.trailing};
- this.client.sendIrcCommand('topic', {server: this.con_num, nick: command.nick, channel: command.params[0], topic: command.trailing});
- },
- 'MODE': function (command) {
- var chanmodes = this.irc_connection.options.CHANMODES,
- prefixes = this.irc_connection.options.PREFIX,
- always_param = chanmodes[0].concat(chanmodes[1]),
- modes = [],
- has_param, i, j, add;
-
- prefixes = _.reduce(prefixes, function (list, prefix) {
- list.push(prefix.mode);
- return list;
- }, []);
- always_param = always_param.split('').concat(prefixes);
-
- has_param = function (mode, add) {
- if (_.find(always_param, function (m) {
- return m === mode;
- })) {
- return true;
- } else if (add && _.find(chanmodes[2].split(''), function (m) {
- return m === mode;
- })) {
- return true;
+ if (this.irc_connection.cap.enabled.length > 0) {
+ if (_.contains(this.irc_connection.cap.enabled, 'sasl')) {
+ this.irc_connection.sasl = true;
+ this.irc_connection.write('AUTHENTICATE PLAIN');
} else {
- return false;
+ this.irc_connection.write('CAP END');
+ this.irc_connection.cap_negotation = false;
}
- };
-
- if (!command.params[1]) {
- command.params[1] = command.trailing;
}
- j = 0;
- for (i = 0; i < command.params[1].length; i++) {
- switch (command.params[1][i]) {
- case '+':
- add = true;
- break;
- case '-':
- add = false;
- break;
- default:
- if (has_param(command.params[1][i], add)) {
- modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: command.params[2 + j]});
- j++;
- } else {
- modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: null});
- }
- }
+ break;
+ case 'NAK':
+ if (capabilities.length > 0) {
+ this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
}
-
- this.client.sendIrcCommand('mode', {
- server: this.con_num,
- target: command.params[0],
- nick: command.nick || command.prefix || '',
- modes: modes
- });
- },
- 'PRIVMSG': function (command) {
- /*command.server = this.con_num;
- command.command = 'PRIVMSG';
- this.client.sendIrcCommand(command);*/
- var tmp, namespace;
- if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
- //CTCP request
- if (command.trailing.substr(1, 6) === 'ACTION') {
- this.client.sendIrcCommand('action', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(7, command.trailing.length - 2)});
- } else if (command.trailing.substr(1, 4) === 'KIWI') {
- tmp = command.trailing.substr(6, command.trailing.length - 2);
- namespace = tmp.split(' ', 1)[0];
- this.client.sendIrcCommand('kiwi', {server: this.con_num, namespace: namespace, data: tmp.substr(namespace.length + 1)});
- } else if (command.trailing.substr(1, 7) === 'VERSION') {
- this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'VERSION KiwiIRC' + String.fromCharCode(1));
- } else {
- this.client.sendIrcCommand('ctcp_request', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing.substr(1, command.trailing.length - 2)});
- }
- } else {
- //{nick: msg.nick, ident: msg.ident, hostname: msg.hostname, channel: msg.params.trim(), msg: msg.trailing}
- this.client.sendIrcCommand('msg', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, channel: command.params[0], msg: command.trailing});
+ if (this.irc_connection.cap.requested.length > 0) {
+ this.irc_connection.write('CAP END');
+ this.irc_connection.cap_negotation = false;
}
- },
- 'ERROR': function (command) {
- /*command.server = this.con_num;
- command.command = 'ERROR';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'error', reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'error', reason: command.trailing});
- },
- ERR_LINKCHANNEL: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_LINKCHANNEL';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('channel_redirect', {from: params[1], to: params[2]});
- this.client.sendIrcCommand('channel_redirect', {server: this.con_num, from: command.params[1], to: command.params[2]});
- },
- ERR_NOSUCHNICK: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_NOSUCHNICK';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'no_such_nick', nick: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'no_such_nick', nick: command.params[1], reason: command.trailing});
- },
- ERR_CANNOTSENDTOCHAN: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_CANNOTSENDTOCHAN';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'cannot_send_to_chan', channel: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'cannot_send_to_chan', channel: command.params[1], reason: command.trailing});
- },
- ERR_TOOMANYCHANNELS: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_TOOMANYCHANNELS';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'too_many_channels', channel: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'too_many_channels', channel: command.params[1], reason: command.trailing});
- },
- ERR_USERNOTINCHANNEL: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_USERNOTINCHANNEL';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'user_not_in_channel', nick: params[0], channel: params[1], reason: msg.trainling});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'user_not_in_channel', nick: command.params[0], channel: command.params[1], reason: command.trailing});
- },
- ERR_NOTONCHANNEL: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_NOTONCHANNEL';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'not_on_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'not_on_channel', channel: command.params[1], reason: command.trailing});
- },
- ERR_CHANNELISFULL: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_CHANNELISFULL';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'channel_is_full', channel: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'channel_is_full', channel: command.params[1], reason: command.trailing});
- },
- ERR_INVITEONLYCHAN: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_INVITEONLYCHAN';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'invite_only_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'invite_only_channel', channel: command.params[1], reason: command.trailing});
- },
- ERR_BANNEDFROMCHAN: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_BANNEDFROMCHAN';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'banned_from_channel', channel: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'banned_from_channel', channel: command.params[1], reason: command.trailing});
- },
- ERR_BADCHANNELKEY: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_BADCHANNELKEY';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'bad_channel_key', channel: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'bad_channel_key', channel: command.params[1], reason: command.trailing});
- },
- ERR_CHANOPRIVSNEEDED: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_CHANOPRIVSNEEDED';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'chanop_privs_needed', channel: msg.params.split(" ")[1], reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'chanop_privs_needed', channel: command.params[1], reason: command.trailing});
- },
- ERR_NICKNAMEINUSE: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_NICKNAMEINUSE';
- this.client.sendIrcCommand(command);*/
- //websocket.sendClientEvent('irc_error', {error: 'nickname_in_use', nick: _.last(msg.params.split(" ")), reason: msg.trailing});
- this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'nickname_in_use', nick: command.params[1], reason: command.trailing});
- },
- ERR_NOTREGISTERED: function (command) {
- /*command.server = this.con_num;
- command.command = 'ERR_NOTREGISTERED';
- this.client.sendIrcCommand(command);*/
+ break;
+ case 'LIST':
+ // should we do anything here?
+ break;
+ }
+ },
+
+ 'AUTHENTICATE': function (command) {
+ var b = new Buffer(this.irc_connection.nick + "\0" + this.irc_connection.nick + "\0" + this.irc_connection.password, 'utf8');
+ var b64 = b.toString('base64');
+ if (command.params[0] === '+') {
+ while (b64.length >= 400) {
+ this.irc_connection.write('AUTHENTICATE ' + b64.slice(0, 399));
+ b64 = b64.slice(399);
+ }
+ if (b64.length > 0) {
+ this.irc_connection.write('AUTHENTICATE ' + b64);
+ } else {
+ this.irc_connection.write('AUTHENTICATE +');
}
+ } else {
+ this.irc_connection.write('CAP END');
+ this.irc_connection.cap_negotation = false;
+ }
+ },
+
+ 'AWAY': function (command) {
+ var time;
+
+ // Check if we have a server-time
+ time = getServerTime.call(this, command);
+
+ this.irc_connection.emit('user ' + command.nick + ' away', {
+ nick: command.nick,
+ msg: command.trailing,
+ time: time
+ });
+ },
+
+ 'RPL_SASLAUTHENTICATED': function (command) {
+ this.irc_connection.write('CAP END');
+ this.irc_connection.cap_negotation = false;
+ this.irc_connection.sasl = true;
+ },
+
+ 'RPL_SASLLOGGEDIN': function (command) {
+ if (this.irc_connection.cap_negotation === false) {
+ this.irc_connection.write('CAP END');
+ }
+ },
+
+ 'ERR_SASLNOTAUTHORISED': function (command) {
+ this.irc_connection.write('CAP END');
+ this.irc_connection.cap_negotation = false;
+ },
+
+ 'ERR_SASLABORTED': function (command) {
+ this.irc_connection.write('CAP END');
+ this.irc_connection.cap_negotation = false;
+ },
+
+ 'ERR_SASLALREADYAUTHED': function (command) {
+ // noop
+ },
+
+ 'ERROR': function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' error', {
+ reason: command.trailing
+ });
+ },
+ ERR_PASSWDMISMATCH: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' password_mismatch', {});
+ },
+
+ ERR_LINKCHANNEL: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' channel_redirect', {
+ from: command.params[1],
+ to: command.params[2]
+ });
+ },
+
+ ERR_NOSUCHNICK: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' no_such_nick', {
+ nick: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_CANNOTSENDTOCHAN: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' cannot_send_to_chan', {
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_TOOMANYCHANNELS: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' too_many_channels', {
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_USERNOTINCHANNEL: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' user_not_in_channel', {
+ nick: command.params[0],
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_NOTONCHANNEL: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' not_on_channel', {
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_USERONCHANNEL: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' user_on_channel', {
+ nick: command.params[1],
+ channel: command.params[2]
+ });
+ },
+
+ ERR_CHANNELISFULL: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' channel_is_full', {
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_INVITEONLYCHAN: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' invite_only_channel', {
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_BANNEDFROMCHAN: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' banned_from_channel', {
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_BADCHANNELKEY: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' bad_channel_key', {
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_CHANOPRIVSNEEDED: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' chanop_privs_needed', {
+ channel: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_NICKNAMEINUSE: function (command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' nickname_in_use', {
+ nick: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_ERRONEUSNICKNAME: function(command) {
+ this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' erroneus_nickname', {
+ nick: command.params[1],
+ reason: command.trailing
+ });
+ },
+
+ ERR_NOTREGISTERED: function (command) {
+ },
+
+ RPL_MAPMORE: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_MAPEND: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_LINKS: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_ENDOFLINKS: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ ERR_UNKNOWNCOMMAND: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, '`' + params.join(', ') + '` ' + command.trailing);
+ },
+
+ ERR_NOMOTD: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, command.trailing);
+ },
+
+ ERR_NOPRIVILEGES: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, command.trailing);
+ },
+
+ RPL_STATSCONN: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_LUSERCLIENT: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_LUSEROP: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_LUSERUNKNOWN: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_LUSERCHANNELS: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_LUSERME: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_LOCALUSERS: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ },
+
+ RPL_GLOBALUSERS: function (command) {
+ var params = _.clone(command.params);
+ params.shift();
+ genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
+ }
};
+
+
+
+
+function genericNotice (command, msg, is_error) {
+ // Default to being an error
+ if (typeof is_error !== 'boolean')
+ is_error = true;
+
+ this.irc_connection.clientEvent('notice', {
+ from_server: true,
+ nick: command.prefix,
+ ident: '',
+ hostname: '',
+ target: command.params[0],
+ msg: msg,
+ numeric: parseInt(command.command, 10)
+ });
+}
+
+
+/**
+ * Convert a mode string such as '+k pass', or '-i' to a readable
+ * format.
+ * [ { mode: '+k', param: 'pass' } ]
+ * [ { mode: '-i', param: null } ]
+ */
+function parseModeList(mode_string, mode_params) {
+ var chanmodes = this.irc_connection.options.CHANMODES || [],
+ prefixes = this.irc_connection.options.PREFIX || [],
+ always_param = (chanmodes[0] || '').concat((chanmodes[1] || '')),
+ modes = [],
+ has_param, i, j, add;
+
+ prefixes = _.reduce(prefixes, function (list, prefix) {
+ list.push(prefix.mode);
+ return list;
+ }, []);
+ always_param = always_param.split('').concat(prefixes);
+
+ has_param = function (mode, add) {
+ if (_.find(always_param, function (m) {
+ return m === mode;
+ })) {
+ return true;
+ } else if (add && _.find((chanmodes[2] || '').split(''), function (m) {
+ return m === mode;
+ })) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ j = 0;
+ for (i = 0; i < mode_string.length; i++) {
+ switch (mode_string[i]) {
+ case '+':
+ add = true;
+ break;
+ case '-':
+ add = false;
+ break;
+ default:
+ if (has_param(mode_string[i], add)) {
+ modes.push({mode: (add ? '+' : '-') + mode_string[i], param: mode_params[j]});
+ j++;
+ } else {
+ modes.push({mode: (add ? '+' : '-') + mode_string[i], param: null});
+ }
+ }
+ }
+
+ return modes;
+}
+
+
+function getServerTime(command) {
+ var time;
+
+ // No tags? No times.
+ if (!command.tags || command.tags.length === 0) {
+ return time;
+ }
+
+ if (capContainsAny.call(this, ['server-time', 'znc.in/server-time', 'znc.in/server-time-iso'])) {
+ time = _.find(command.tags, function (tag) {
+ return tag.tag === 'time';
+ });
+
+ time = time ? time.value : undefined;
+
+ // Convert the time value to a unixtimestamp
+ if (typeof time === 'string') {
+ if (time.indexOf('T') > -1) {
+ time = parseISO8601(time);
+
+ } else if(time.match(/^[0-9.]+$/)) {
+ // A string formatted unix timestamp
+ time = new Date(time * 1000);
+ }
+
+ time = time.getTime();
+
+ } else if (typeof time === 'number') {
+ time = new Date(time * 1000);
+ time = time.getTime();
+ }
+ }
+
+ return time;
+}
+
+
+function capContainsAny (caps) {
+ var intersection;
+ if (!caps instanceof Array) {
+ caps = [caps];
+ }
+ intersection = _.intersection(this.irc_connection.cap.enabled, caps);
+ return intersection.length > 0;
+}
+
+
+// Code based on http://anentropic.wordpress.com/2009/06/25/javascript-iso8601-parser-and-pretty-dates/#comment-154
+function parseISO8601(str) {
+ if (Date.prototype.toISOString) {
+ return new Date(str);
+ } else {
+ var parts = str.split('T'),
+ dateParts = parts[0].split('-'),
+ timeParts = parts[1].split('Z'),
+ timeSubParts = timeParts[0].split(':'),
+ timeSecParts = timeSubParts[2].split('.'),
+ timeHours = Number(timeSubParts[0]),
+ _date = new Date();
+
+ _date.setUTCFullYear(Number(dateParts[0]));
+ _date.setUTCDate(1);
+ _date.setUTCMonth(Number(dateParts[1])-1);
+ _date.setUTCDate(Number(dateParts[2]));
+ _date.setUTCHours(Number(timeHours));
+ _date.setUTCMinutes(Number(timeSubParts[1]));
+ _date.setUTCSeconds(Number(timeSecParts[0]));
+ if (timeSecParts[1]) {
+ _date.setUTCMilliseconds(Number(timeSecParts[1]));
+ }
+
+ return _date;
+ }
+}