| 1 | var _ = require('lodash'); |
| 2 | |
| 3 | var irc_numerics = { |
| 4 | RPL_WELCOME: '001', |
| 5 | RPL_MYINFO: '004', |
| 6 | RPL_ISUPPORT: '005', |
| 7 | RPL_MAPMORE: '006', |
| 8 | RPL_MAPEND: '007', |
| 9 | RPL_WHOISREGNICK: '307', |
| 10 | RPL_WHOISUSER: '311', |
| 11 | RPL_WHOISSERVER: '312', |
| 12 | RPL_WHOISOPERATOR: '313', |
| 13 | RPL_WHOISIDLE: '317', |
| 14 | RPL_ENDOFWHOIS: '318', |
| 15 | RPL_WHOISCHANNELS: '319', |
| 16 | RPL_LISTSTART: '321', |
| 17 | RPL_LIST: '322', |
| 18 | RPL_LISTEND: '323', |
| 19 | RPL_NOTOPIC: '331', |
| 20 | RPL_TOPIC: '332', |
| 21 | RPL_TOPICWHOTIME: '333', |
| 22 | RPL_NAMEREPLY: '353', |
| 23 | RPL_LINKS: '364', |
| 24 | RPL_ENDOFLINKS: '365', |
| 25 | RPL_ENDOFNAMES: '366', |
| 26 | RPL_BANLIST: '367', |
| 27 | RPL_ENDOFBANLIST: '368', |
| 28 | RPL_MOTD: '372', |
| 29 | RPL_MOTDSTART: '375', |
| 30 | RPL_ENDOFMOTD: '376', |
| 31 | RPL_WHOISMODES: '379', |
| 32 | ERR_NOSUCHNICK: '401', |
| 33 | ERR_CANNOTSENDTOCHAN: '404', |
| 34 | ERR_TOOMANYCHANNELS: '405', |
| 35 | ERR_UNKNOWNCOMMAND: '421', |
| 36 | ERR_NOMOTD: '422', |
| 37 | ERR_NICKNAMEINUSE: '433', |
| 38 | ERR_USERNOTINCHANNEL: '441', |
| 39 | ERR_NOTONCHANNEL: '442', |
| 40 | ERR_NOTREGISTERED: '451', |
| 41 | ERR_LINKCHANNEL: '470', |
| 42 | ERR_CHANNELISFULL: '471', |
| 43 | ERR_INVITEONLYCHAN: '473', |
| 44 | ERR_BANNEDFROMCHAN: '474', |
| 45 | ERR_BADCHANNELKEY: '475', |
| 46 | ERR_NOPRIVILEGES: '481', |
| 47 | ERR_CHANOPRIVSNEEDED: '482', |
| 48 | RPL_STARTTLS: '670', |
| 49 | RPL_SASLAUTHENTICATED: '900', |
| 50 | RPL_SASLLOGGEDIN: '903', |
| 51 | ERR_SASLNOTAUTHORISED: '904', |
| 52 | ERR_SASLABORTED: '906', |
| 53 | ERR_SASLALREADYAUTHED: '907' |
| 54 | |
| 55 | }; |
| 56 | |
| 57 | |
| 58 | var IrcCommands = function (irc_connection, con_num, client) { |
| 59 | this.irc_connection = irc_connection; |
| 60 | this.con_num = con_num; |
| 61 | this.client = client; |
| 62 | }; |
| 63 | module.exports = IrcCommands; |
| 64 | |
| 65 | IrcCommands.prototype.bindEvents = function () { |
| 66 | var that = this; |
| 67 | |
| 68 | _.each(listeners, function (listener, command) { |
| 69 | var s = command.substr(0, 4); |
| 70 | if ((s === 'RPL_') || (s === 'ERR_')) { |
| 71 | command = irc_numerics[command]; |
| 72 | } |
| 73 | that.irc_connection.on('irc_' + command, function () { |
| 74 | listener.apply(that, arguments); |
| 75 | }); |
| 76 | }); |
| 77 | }; |
| 78 | |
| 79 | IrcCommands.prototype.dispose = function () { |
| 80 | this.removeAllListeners(); |
| 81 | }; |
| 82 | |
| 83 | |
| 84 | |
| 85 | var listeners = { |
| 86 | 'RPL_WELCOME': function (command) { |
| 87 | var nick = command.params[0]; |
| 88 | this.irc_connection.registered = true; |
| 89 | this.cap_negotation = false; |
| 90 | this.client.sendIrcCommand('connect', {server: this.con_num, nick: nick}); |
| 91 | }, |
| 92 | 'RPL_ISUPPORT': function (command) { |
| 93 | var options, i, option, matches, j; |
| 94 | options = command.params; |
| 95 | for (i = 1; i < options.length; i++) { |
| 96 | option = options[i].split("=", 2); |
| 97 | option[0] = option[0].toUpperCase(); |
| 98 | this.irc_connection.options[option[0]] = (typeof option[1] !== 'undefined') ? option[1] : true; |
| 99 | if (_.include(['NETWORK', 'PREFIX', 'CHANTYPES', 'CHANMODES', 'NAMESX'], option[0])) { |
| 100 | if (option[0] === 'PREFIX') { |
| 101 | matches = /\(([^)]*)\)(.*)/.exec(option[1]); |
| 102 | if ((matches) && (matches.length === 3)) { |
| 103 | this.irc_connection.options.PREFIX = []; |
| 104 | for (j = 0; j < matches[2].length; j++) { |
| 105 | this.irc_connection.options.PREFIX.push({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)}); |
| 106 | } |
| 107 | } |
| 108 | } else if (option[0] === 'CHANTYPES') { |
| 109 | this.irc_connection.options.CHANTYPES = this.irc_connection.options.CHANTYPES.split(''); |
| 110 | } else if (option[0] === 'CHANMODES') { |
| 111 | this.irc_connection.options.CHANMODES = option[1].split(','); |
| 112 | } else if ((option[0] === 'NAMESX') && (!_.contains(this.irc_connection.cap.enabled, 'multi-prefix'))) { |
| 113 | this.irc_connection.write('PROTOCTL NAMESX'); |
| 114 | } |
| 115 | } |
| 116 | } |
| 117 | this.client.sendIrcCommand('options', {server: this.con_num, options: this.irc_connection.options, cap: this.irc_connection.cap.enabled}); |
| 118 | }, |
| 119 | 'RPL_ENDOFWHOIS': function (command) { |
| 120 | this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: true}); |
| 121 | }, |
| 122 | 'RPL_WHOISUSER': function (command) { |
| 123 | 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}); |
| 124 | }, |
| 125 | 'RPL_WHOISSERVER': function (command) { |
| 126 | this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], irc_server: command.params[2], end: false}); |
| 127 | }, |
| 128 | 'RPL_WHOISOPERATOR': function (command) { |
| 129 | this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false}); |
| 130 | }, |
| 131 | 'RPL_WHOISCHANNELS': function (command) { |
| 132 | this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], chans: command.trailing, end: false}); |
| 133 | }, |
| 134 | 'RPL_WHOISMODES': function (command) { |
| 135 | this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false}); |
| 136 | }, |
| 137 | 'RPL_WHOISIDLE': function (command) { |
| 138 | if (command.params[3]) { |
| 139 | this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], logon: command.params[3], end: false}); |
| 140 | } else { |
| 141 | this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], idle: command.params[2], end: false}); |
| 142 | } |
| 143 | }, |
| 144 | 'RPL_WHOISREGNICK': function (command) { |
| 145 | this.client.sendIrcCommand('whois', {server: this.con_num, nick: command.params[1], msg: command.trailing, end: false}); |
| 146 | }, |
| 147 | 'RPL_LISTSTART': function (command) { |
| 148 | this.client.sendIrcCommand('list_start', {server: this.con_num}); |
| 149 | this.client.buffer.list = []; |
| 150 | }, |
| 151 | 'RPL_LISTEND': function (command) { |
| 152 | if (this.client.buffer.list.length > 0) { |
| 153 | this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) { |
| 154 | return channel.num_users; |
| 155 | }); |
| 156 | this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list}); |
| 157 | this.client.buffer.list = []; |
| 158 | } |
| 159 | this.client.sendIrcCommand('list_end', {server: this.con_num}); |
| 160 | }, |
| 161 | 'RPL_LIST': function (command) { |
| 162 | this.client.buffer.list.push({server: this.con_num, channel: command.params[1], num_users: parseInt(command.params[2], 10), topic: command.trailing}); |
| 163 | if (this.client.buffer.list.length > 200){ |
| 164 | this.client.buffer.list = _.sortBy(this.client.buffer.list, function (channel) { |
| 165 | return channel.num_users; |
| 166 | }); |
| 167 | this.client.sendIrcCommand('list_channel', {server: this.con_num, chans: this.client.buffer.list}); |
| 168 | this.client.buffer.list = []; |
| 169 | } |
| 170 | }, |
| 171 | 'RPL_MOTD': function (command) { |
| 172 | this.client.buffer.motd += command.trailing + '\n'; |
| 173 | }, |
| 174 | 'RPL_MOTDSTART': function (command) { |
| 175 | this.client.buffer.motd = ''; |
| 176 | }, |
| 177 | 'RPL_ENDOFMOTD': function (command) { |
| 178 | this.client.sendIrcCommand('motd', {server: this.con_num, msg: this.client.buffer.motd}); |
| 179 | }, |
| 180 | 'RPL_NAMEREPLY': function (command) { |
| 181 | var members = command.trailing.split(' '); |
| 182 | var member_list = []; |
| 183 | var that = this; |
| 184 | var i = 0; |
| 185 | _.each(members, function (member) { |
| 186 | var j, k, modes = []; |
| 187 | |
| 188 | // Make sure we have some prefixes already |
| 189 | if (that.irc_connection.options.PREFIX) { |
| 190 | for (j = 0; j < member.length; j++) { |
| 191 | for (k = 0; k < that.irc_connection.options.PREFIX.length; k++) { |
| 192 | if (member.charAt(j) === that.irc_connection.options.PREFIX[k].symbol) { |
| 193 | modes.push(that.irc_connection.options.PREFIX[k].mode); |
| 194 | i++; |
| 195 | } |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | member_list.push({nick: member, modes: modes}); |
| 201 | }); |
| 202 | |
| 203 | that.irc_connection.emit('channel:' + command.params[2] + ':userlist', { |
| 204 | users: member_list, |
| 205 | channel: command.params[2] |
| 206 | }); |
| 207 | }, |
| 208 | |
| 209 | |
| 210 | 'RPL_ENDOFNAMES': function (command) { |
| 211 | that.irc_connection.emit('channel:' + command.params[1] + ':userlist_end', { |
| 212 | channel: command.params[1] |
| 213 | }); |
| 214 | }, |
| 215 | |
| 216 | |
| 217 | 'RPL_BANLIST': function (command) { |
| 218 | 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]}); |
| 219 | }, |
| 220 | 'RPL_ENDOFBANLIST': function (command) { |
| 221 | this.client.sendIrcCommand('banlist_end', {server: this.con_num, channel: command.params[1]}); |
| 222 | }, |
| 223 | 'RPL_TOPIC': function (command) { |
| 224 | this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: command.trailing}); |
| 225 | }, |
| 226 | 'RPL_NOTOPIC': function (command) { |
| 227 | this.client.sendIrcCommand('topic', {server: this.con_num, nick: '', channel: command.params[1], topic: ''}); |
| 228 | }, |
| 229 | 'RPL_TOPICWHOTIME': function (command) { |
| 230 | this.client.sendIrcCommand('topicsetby', {server: this.con_num, nick: command.params[2], channel: command.params[1], when: command.params[3]}); |
| 231 | }, |
| 232 | 'PING': function (command) { |
| 233 | this.irc_connection.write('PONG ' + command.trailing); |
| 234 | }, |
| 235 | |
| 236 | |
| 237 | 'JOIN': function (command) { |
| 238 | var channel; |
| 239 | if (typeof command.trailing === 'string' && command.trailing !== '') { |
| 240 | channel = command.trailing; |
| 241 | } else if (typeof command.params[0] === 'string' && command.params[0] !== '') { |
| 242 | channel = command.params[0]; |
| 243 | } |
| 244 | |
| 245 | this.irc_connection.emit('channel:' + channel + ':join', { |
| 246 | nick: command.nick, |
| 247 | ident: command.ident, |
| 248 | hostname: command.hostname, |
| 249 | channel: channel |
| 250 | }); |
| 251 | }, |
| 252 | |
| 253 | |
| 254 | 'PART': function (command) { |
| 255 | this.irc_connection.emit('channel:' + command.params[0] + ':part', { |
| 256 | nick: command.nick, |
| 257 | ident: command.ident, |
| 258 | hostname: command.hostname, |
| 259 | channel: command.params[0], |
| 260 | message: command.trailing |
| 261 | }); |
| 262 | }, |
| 263 | |
| 264 | |
| 265 | 'KICK': function (command) { |
| 266 | this.irc_connection.emit('channel:' + command.params[0] + ':kick', { |
| 267 | kicked: command.params[1], |
| 268 | nick: command.nick, |
| 269 | ident: command.ident, |
| 270 | hostname: command.hostname, |
| 271 | channel: command.params[0], |
| 272 | message: command.trailing |
| 273 | }); |
| 274 | }, |
| 275 | |
| 276 | |
| 277 | 'QUIT': function (command) { |
| 278 | this.irc_connection.emit('user:' + command.nick + ':quit', { |
| 279 | nick: command.nick, |
| 280 | ident: command.ident, |
| 281 | hostname: command.hostname, |
| 282 | message: command.trailing |
| 283 | }); |
| 284 | }, |
| 285 | |
| 286 | |
| 287 | 'NOTICE': function (command) { |
| 288 | var namespace; |
| 289 | |
| 290 | if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) { |
| 291 | // It's a CTCP response |
| 292 | namespace = (command.params[0] == this.irc_connection.nick) ? 'user' : 'channel'; |
| 293 | this.irc_connection.emit(namespace + ':' + command.params[0] + ':ctcp_response', { |
| 294 | nick: command.nick, |
| 295 | ident: command.ident, |
| 296 | hostname: command.hostname, |
| 297 | channel: command.params[0], |
| 298 | msg: command.trailing.substr(1, command.trailing.length - 2) |
| 299 | }); |
| 300 | } else { |
| 301 | namespace = (command.params[0] == this.irc_connection.nick) ? 'user' : 'channel'; |
| 302 | this.irc_connection.emit(namespace + ':' + command.params[0] + ':notice', { |
| 303 | nick: command.nick, |
| 304 | ident: command.ident, |
| 305 | hostname: command.hostname, |
| 306 | target: command.params[0], |
| 307 | msg: command.trailing |
| 308 | }); |
| 309 | } |
| 310 | }, |
| 311 | 'NICK': function (command) { |
| 312 | this.client.sendIrcCommand('nick', {server: this.con_num, nick: command.nick, ident: command.ident, hostname: command.hostname, newnick: command.trailing || command.params[0]}); |
| 313 | }, |
| 314 | 'TOPIC': function (command) { |
| 315 | // If we don't have an associated channel, no need to continue |
| 316 | if (!command.params[0]) return; |
| 317 | |
| 318 | var channel = command.params[0], |
| 319 | topic = command.trailing || ''; |
| 320 | |
| 321 | this.irc_connection.emit('channel:' + channel + ':topic', { |
| 322 | nick: command.nick, |
| 323 | channel: channel, |
| 324 | topic: topic |
| 325 | }); |
| 326 | }, |
| 327 | 'MODE': function (command) { |
| 328 | var chanmodes = this.irc_connection.options.CHANMODES || [], |
| 329 | prefixes = this.irc_connection.options.PREFIX || [], |
| 330 | always_param = (chanmodes[0] || '').concat((chanmodes[1] || '')), |
| 331 | modes = [], |
| 332 | has_param, i, j, add; |
| 333 | |
| 334 | prefixes = _.reduce(prefixes, function (list, prefix) { |
| 335 | list.push(prefix.mode); |
| 336 | return list; |
| 337 | }, []); |
| 338 | always_param = always_param.split('').concat(prefixes); |
| 339 | |
| 340 | has_param = function (mode, add) { |
| 341 | if (_.find(always_param, function (m) { |
| 342 | return m === mode; |
| 343 | })) { |
| 344 | return true; |
| 345 | } else if (add && _.find((chanmodes[2] || '').split(''), function (m) { |
| 346 | return m === mode; |
| 347 | })) { |
| 348 | return true; |
| 349 | } else { |
| 350 | return false; |
| 351 | } |
| 352 | }; |
| 353 | |
| 354 | if (!command.params[1]) { |
| 355 | command.params[1] = command.trailing; |
| 356 | } |
| 357 | j = 0; |
| 358 | for (i = 0; i < command.params[1].length; i++) { |
| 359 | switch (command.params[1][i]) { |
| 360 | case '+': |
| 361 | add = true; |
| 362 | break; |
| 363 | case '-': |
| 364 | add = false; |
| 365 | break; |
| 366 | default: |
| 367 | if (has_param(command.params[1][i], add)) { |
| 368 | modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: command.params[2 + j]}); |
| 369 | j++; |
| 370 | } else { |
| 371 | modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: null}); |
| 372 | } |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | this.client.sendIrcCommand('mode', { |
| 377 | server: this.con_num, |
| 378 | target: command.params[0], |
| 379 | nick: command.nick || command.prefix || '', |
| 380 | modes: modes |
| 381 | }); |
| 382 | }, |
| 383 | 'PRIVMSG': function (command) { |
| 384 | var tmp, namespace; |
| 385 | if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) { |
| 386 | //CTCP request |
| 387 | if (command.trailing.substr(1, 6) === 'ACTION') { |
| 388 | 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)}); |
| 389 | } else if (command.trailing.substr(1, 4) === 'KIWI') { |
| 390 | tmp = command.trailing.substr(6, command.trailing.length - 2); |
| 391 | namespace = tmp.split(' ', 1)[0]; |
| 392 | this.client.sendIrcCommand('kiwi', {server: this.con_num, namespace: namespace, data: tmp.substr(namespace.length + 1)}); |
| 393 | } else if (command.trailing.substr(1, 7) === 'VERSION') { |
| 394 | this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'VERSION KiwiIRC' + String.fromCharCode(1)); |
| 395 | } else if (command.trailing.substr(1, 6) === 'SOURCE') { |
| 396 | this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'SOURCE http://www.kiwiirc.com/' + String.fromCharCode(1)); |
| 397 | } else if (command.trailing.substr(1, 10) === 'CLIENTINFO') { |
| 398 | this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'CLIENTINFO SOURCE VERSION TIME' + String.fromCharCode(1)); |
| 399 | } else { |
| 400 | namespace = (command.target == this.irc_connection.nick) ? 'user' : 'channel'; |
| 401 | this.irc_connection.emit(namespace + ':' + command.nick + ':ctcp_request', { |
| 402 | nick: command.nick, |
| 403 | ident: command.ident, |
| 404 | hostname: command.hostname, |
| 405 | target: command.params[0], |
| 406 | type: (command.trailing.substr(1, command.trailing.length - 2).split(' ') || [null])[0], |
| 407 | msg: command.trailing.substr(1, command.trailing.length - 2) |
| 408 | }); |
| 409 | } |
| 410 | } else { |
| 411 | // A message to a user (private message) or to a channel? |
| 412 | namespace = (command.target == this.irc_connection.nick) ? 'user' : 'channel'; |
| 413 | this.irc_connection.emit(namespace + ':' + command.nick + ':privmsg', { |
| 414 | nick: command.nick, |
| 415 | ident: command.ident, |
| 416 | hostname: command.hostname, |
| 417 | channel: command.params[0], |
| 418 | msg: command.trailing |
| 419 | ); |
| 420 | } |
| 421 | }, |
| 422 | 'CAP': function (command) { |
| 423 | // TODO: capability modifiers |
| 424 | // i.e. - for disable, ~ for requires ACK, = for sticky |
| 425 | var capabilities = command.trailing.replace(/[\-~=]/, '').split(' '); |
| 426 | var request; |
| 427 | var want = ['multi-prefix', 'away-notify']; |
| 428 | |
| 429 | if (this.irc_connection.password) { |
| 430 | want.push('sasl'); |
| 431 | } |
| 432 | |
| 433 | switch (command.params[1]) { |
| 434 | case 'LS': |
| 435 | request = _.intersection(capabilities, want); |
| 436 | if (request.length > 0) { |
| 437 | this.irc_connection.cap.requested = request; |
| 438 | this.irc_connection.write('CAP REQ :' + request.join(' ')); |
| 439 | } else { |
| 440 | this.irc_connection.write('CAP END'); |
| 441 | this.irc_connection.cap_negotation = false; |
| 442 | } |
| 443 | break; |
| 444 | case 'ACK': |
| 445 | if (capabilities.length > 0) { |
| 446 | this.irc_connection.cap.enabled = capabilities; |
| 447 | this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities); |
| 448 | } |
| 449 | if (this.irc_connection.cap.requested.length > 0) { |
| 450 | if (_.contains(this.irc_connection.cap.enabled, 'sasl')) { |
| 451 | this.irc_connection.sasl = true; |
| 452 | this.irc_connection.write('AUTHENTICATE PLAIN'); |
| 453 | } else { |
| 454 | this.irc_connection.write('CAP END'); |
| 455 | this.irc_connection.cap_negotation = false; |
| 456 | } |
| 457 | } |
| 458 | break; |
| 459 | case 'NAK': |
| 460 | if (capabilities.length > 0) { |
| 461 | this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities); |
| 462 | } |
| 463 | if (this.irc_connection.cap.requested.length > 0) { |
| 464 | this.irc_connection.write('CAP END'); |
| 465 | this.irc_connection.cap_negotation = false; |
| 466 | } |
| 467 | break; |
| 468 | case 'LIST': |
| 469 | // should we do anything here? |
| 470 | break; |
| 471 | } |
| 472 | }, |
| 473 | 'AUTHENTICATE': function (command) { |
| 474 | var b = new Buffer(this.irc_connection.nick + "\0" + this.irc_connection.nick + "\0" + this.irc_connection.password, 'utf8'); |
| 475 | var b64 = b.toString('base64'); |
| 476 | if (command.params[0] === '+') { |
| 477 | while (b64.length >= 400) { |
| 478 | this.irc_connection.write('AUTHENTICATE ' + b64.slice(0, 399)); |
| 479 | b64 = b64.slice(399); |
| 480 | } |
| 481 | if (b64.length > 0) { |
| 482 | this.irc_connection.write('AUTHENTICATE ' + b64); |
| 483 | } else { |
| 484 | this.irc_connection.write('AUTHENTICATE +'); |
| 485 | } |
| 486 | } else { |
| 487 | this.irc_connection.write('CAP END'); |
| 488 | this.irc_connection.cap_negotation = false; |
| 489 | } |
| 490 | }, |
| 491 | 'AWAY': function (command) { |
| 492 | this.client.sendIrcCommand('away', {server: this.con_num, nick: command.nick, msg: command.trailing}); |
| 493 | }, |
| 494 | 'RPL_SASLAUTHENTICATED': function (command) { |
| 495 | this.irc_connection.write('CAP END'); |
| 496 | this.irc_connection.cap_negotation = false; |
| 497 | this.irc_connection.sasl = true; |
| 498 | }, |
| 499 | 'RPL_SASLLOGGEDIN': function (command) { |
| 500 | if (this.irc_connection.cap_negotation === false) { |
| 501 | this.irc_connection.write('CAP END'); |
| 502 | } |
| 503 | }, |
| 504 | 'ERR_SASLNOTAUTHORISED': function (command) { |
| 505 | this.irc_connection.write('CAP END'); |
| 506 | this.irc_connection.cap_negotation = false; |
| 507 | }, |
| 508 | 'ERR_SASLABORTED': function (command) { |
| 509 | this.irc_connection.write('CAP END'); |
| 510 | this.irc_connection.cap_negotation = false; |
| 511 | }, |
| 512 | 'ERR_SASLALREADYAUTHED': function (command) { |
| 513 | // noop |
| 514 | }, |
| 515 | 'ERROR': function (command) { |
| 516 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'error', reason: command.trailing}); |
| 517 | }, |
| 518 | ERR_LINKCHANNEL: function (command) { |
| 519 | this.client.sendIrcCommand('channel_redirect', {server: this.con_num, from: command.params[1], to: command.params[2]}); |
| 520 | }, |
| 521 | ERR_NOSUCHNICK: function (command) { |
| 522 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'no_such_nick', nick: command.params[1], reason: command.trailing}); |
| 523 | }, |
| 524 | ERR_CANNOTSENDTOCHAN: function (command) { |
| 525 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'cannot_send_to_chan', channel: command.params[1], reason: command.trailing}); |
| 526 | }, |
| 527 | ERR_TOOMANYCHANNELS: function (command) { |
| 528 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'too_many_channels', channel: command.params[1], reason: command.trailing}); |
| 529 | }, |
| 530 | ERR_USERNOTINCHANNEL: function (command) { |
| 531 | 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}); |
| 532 | }, |
| 533 | ERR_NOTONCHANNEL: function (command) { |
| 534 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'not_on_channel', channel: command.params[1], reason: command.trailing}); |
| 535 | }, |
| 536 | ERR_CHANNELISFULL: function (command) { |
| 537 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'channel_is_full', channel: command.params[1], reason: command.trailing}); |
| 538 | }, |
| 539 | ERR_INVITEONLYCHAN: function (command) { |
| 540 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'invite_only_channel', channel: command.params[1], reason: command.trailing}); |
| 541 | }, |
| 542 | ERR_BANNEDFROMCHAN: function (command) { |
| 543 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'banned_from_channel', channel: command.params[1], reason: command.trailing}); |
| 544 | }, |
| 545 | ERR_BADCHANNELKEY: function (command) { |
| 546 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'bad_channel_key', channel: command.params[1], reason: command.trailing}); |
| 547 | }, |
| 548 | ERR_CHANOPRIVSNEEDED: function (command) { |
| 549 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'chanop_privs_needed', channel: command.params[1], reason: command.trailing}); |
| 550 | }, |
| 551 | ERR_NICKNAMEINUSE: function (command) { |
| 552 | this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'nickname_in_use', nick: command.params[1], reason: command.trailing}); |
| 553 | }, |
| 554 | ERR_NOTREGISTERED: function (command) { |
| 555 | }, |
| 556 | |
| 557 | RPL_MAPMORE: function (command) { |
| 558 | var params = _.clone(command.params); |
| 559 | params.shift(); |
| 560 | genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing); |
| 561 | }, |
| 562 | RPL_MAPEND: function (command) { |
| 563 | var params = _.clone(command.params); |
| 564 | params.shift(); |
| 565 | genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing); |
| 566 | }, |
| 567 | |
| 568 | RPL_LINKS: function (command) { |
| 569 | var params = _.clone(command.params); |
| 570 | params.shift(); |
| 571 | genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing); |
| 572 | }, |
| 573 | RPL_ENDOFLINKS: function (command) { |
| 574 | var params = _.clone(command.params); |
| 575 | params.shift(); |
| 576 | genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing); |
| 577 | }, |
| 578 | |
| 579 | ERR_UNKNOWNCOMMAND: function (command) { |
| 580 | var params = _.clone(command.params); |
| 581 | params.shift(); |
| 582 | genericNotice.call(this, command, '`' + params.join(', ') + '` ' + command.trailing); |
| 583 | }, |
| 584 | |
| 585 | ERR_NOMOTD: function (command) { |
| 586 | var params = _.clone(command.params); |
| 587 | params.shift(); |
| 588 | genericNotice.call(this, command, command.trailing); |
| 589 | }, |
| 590 | |
| 591 | ERR_NOPRIVILEGES: function (command) { |
| 592 | var params = _.clone(command.params); |
| 593 | params.shift(); |
| 594 | genericNotice.call(this, command, command.trailing); |
| 595 | } |
| 596 | }; |
| 597 | |
| 598 | |
| 599 | |
| 600 | |
| 601 | function genericNotice (command, msg, is_error) { |
| 602 | // Default to being an error |
| 603 | if (typeof is_error !== 'boolean') |
| 604 | is_error = true; |
| 605 | |
| 606 | this.client.sendIrcCommand('notice', { |
| 607 | server: this.con_num, |
| 608 | nick: command.prefix, |
| 609 | ident: '', |
| 610 | hostname: '', |
| 611 | target: command.params[0], |
| 612 | msg: msg, |
| 613 | numeric: parseInt(command.command, 10) |
| 614 | }); |
| 615 | } |