Unknown IRC commands sent to client; RPL_WHOISACCOUNT, RPL_WHOISHOST, ERR_USERONCHANN...
[KiwiIRC.git] / server / irc / commands.js
1 var _ = require('lodash'),
2 irc_numerics,
3 IrcCommands,
4 handlers,
5 unknownCommand;
6
7 irc_numerics = {
8 '001': 'RPL_WELCOME',
9 '004': 'RPL_MYINFO',
10 '005': 'RPL_ISUPPORT',
11 '006': 'RPL_MAPMORE',
12 '007': 'RPL_MAPEND',
13 '250': 'RPL_STATSCONN',
14 '251': 'RPL_LUSERCLIENT',
15 '252': 'RPL_LUSEROP',
16 '253': 'RPL_LUSERUNKNOWN',
17 '254': 'RPL_LUSERCHANNELS',
18 '255': 'RPL_LUSERME',
19 '265': 'RPL_LOCALUSERS',
20 '266': 'RPL_GLOBALUSERS',
21 '301': 'RPL_AWAY',
22 '307': 'RPL_WHOISREGNICK',
23 '311': 'RPL_WHOISUSER',
24 '312': 'RPL_WHOISSERVER',
25 '313': 'RPL_WHOISOPERATOR',
26 '314': 'RPL_WHOWASUSER',
27 '317': 'RPL_WHOISIDLE',
28 '318': 'RPL_ENDOFWHOIS',
29 '319': 'RPL_WHOISCHANNELS',
30 '321': 'RPL_LISTSTART',
31 '322': 'RPL_LIST',
32 '323': 'RPL_LISTEND',
33 '330': 'RPL_WHOISACCOUNT',
34 '331': 'RPL_NOTOPIC',
35 '332': 'RPL_TOPIC',
36 '333': 'RPL_TOPICWHOTIME',
37 '353': 'RPL_NAMEREPLY',
38 '364': 'RPL_LINKS',
39 '365': 'RPL_ENDOFLINKS',
40 '366': 'RPL_ENDOFNAMES',
41 '367': 'RPL_BANLIST',
42 '368': 'RPL_ENDOFBANLIST',
43 '369': 'RPL_ENDOFWHOWAS',
44 '372': 'RPL_MOTD',
45 '375': 'RPL_MOTDSTART',
46 '376': 'RPL_ENDOFMOTD',
47 '378': 'RPL_WHOISHOST',
48 '379': 'RPL_WHOISMODES',
49 '401': 'ERR_NOSUCHNICK',
50 '404': 'ERR_CANNOTSENDTOCHAN',
51 '405': 'ERR_TOOMANYCHANNELS',
52 '406': 'ERR_WASNOSUCHNICK',
53 '421': 'ERR_UNKNOWNCOMMAND',
54 '422': 'ERR_NOMOTD',
55 '432': 'ERR_ERRONEUSNICKNAME',
56 '433': 'ERR_NICKNAMEINUSE',
57 '441': 'ERR_USERNOTINCHANNEL',
58 '442': 'ERR_NOTONCHANNEL',
59 '443': 'ERR_USERONCHANNEL',
60 '451': 'ERR_NOTREGISTERED',
61 '464': 'ERR_PASSWDMISMATCH',
62 '470': 'ERR_LINKCHANNEL',
63 '471': 'ERR_CHANNELISFULL',
64 '473': 'ERR_INVITEONLYCHAN',
65 '474': 'ERR_BANNEDFROMCHAN',
66 '475': 'ERR_BADCHANNELKEY',
67 '481': 'ERR_NOPRIVILEGES',
68 '482': 'ERR_CHANOPRIVSNEEDED',
69 '670': 'RPL_STARTTLS',
70 '671': 'RPL_WHOISSECURE',
71 '900': 'RPL_SASLAUTHENTICATED',
72 '903': 'RPL_SASLLOGGEDIN',
73 '904': 'ERR_SASLNOTAUTHORISED',
74 '906': 'ERR_SASLABORTED',
75 '907': 'ERR_SASLALREADYAUTHED'
76 };
77
78
79 IrcCommands = function (irc_connection) {
80 this.irc_connection = irc_connection;
81 };
82 module.exports = IrcCommands;
83
84 IrcCommands.prototype.dispatch = function (command, data) {
85 command += '';
86 if (irc_numerics[command]) {
87 command = irc_numerics[command];
88 }
89 if (handlers[command]) {
90 handlers[command].call(this, data);
91 } else {
92 unknownCommand.call(this, command, data);
93 }
94 };
95
96 IrcCommands.addHandler = function (command, handler) {
97 if (typeof handler !== 'function') {
98 return false;
99 }
100 handlers[command] = handler;
101 };
102
103 IrcCommands.addNumeric = function (numeric, handler_name) {
104 irc_numerics[numeric + ''] = handler_name +'';
105 };
106
107 unknownCommand = function (command, data) {
108 var params = _.clone(data.params);
109
110 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' unknown_command', {
111 command: command,
112 params: params,
113 trailing: data.trailing
114 });
115
116
117 /*
118 this.irc_connection.emit(namespace + ' ' + command.params[0] + ' notice', {
119 from_server: command.prefix ? true : false,
120 nick: command.nick || command.prefix || undefined,
121 ident: command.ident,
122 hostname: command.hostname,
123 target: command.params[0],
124 msg: command.trailing
125 });
126 */
127 };
128
129
130 handlers = {
131 'RPL_WELCOME': function (command) {
132 var nick = command.params[0];
133 this.irc_connection.registered = true;
134 this.cap_negotation = false;
135 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' connect', {
136 nick: nick
137 });
138 },
139
140 'RPL_ISUPPORT': function (command) {
141 var options, i, option, matches, j;
142 options = command.params;
143 for (i = 1; i < options.length; i++) {
144 option = options[i].split("=", 2);
145 option[0] = option[0].toUpperCase();
146 this.irc_connection.options[option[0]] = (typeof option[1] !== 'undefined') ? option[1] : true;
147 if (_.include(['NETWORK', 'PREFIX', 'CHANTYPES', 'CHANMODES', 'NAMESX'], option[0])) {
148 if (option[0] === 'PREFIX') {
149 matches = /\(([^)]*)\)(.*)/.exec(option[1]);
150 if ((matches) && (matches.length === 3)) {
151 this.irc_connection.options.PREFIX = [];
152 for (j = 0; j < matches[2].length; j++) {
153 this.irc_connection.options.PREFIX.push({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
154 }
155 }
156 } else if (option[0] === 'CHANTYPES') {
157 this.irc_connection.options.CHANTYPES = this.irc_connection.options.CHANTYPES.split('');
158 } else if (option[0] === 'CHANMODES') {
159 this.irc_connection.options.CHANMODES = option[1].split(',');
160 } else if ((option[0] === 'NAMESX') && (!_.contains(this.irc_connection.cap.enabled, 'multi-prefix'))) {
161 this.irc_connection.write('PROTOCTL NAMESX');
162 }
163 }
164 }
165 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' options', {
166 options: this.irc_connection.options,
167 cap: this.irc_connection.cap.enabled
168 });
169 },
170
171 'RPL_ENDOFWHOIS': function (command) {
172 this.irc_connection.emit('user ' + command.params[1] + ' endofwhois', {
173 nick: command.params[1],
174 msg: command.trailing
175 });
176 },
177
178 'RPL_AWAY': function (command) {
179 this.irc_connection.emit('user ' + command.params[1] + ' whoisaway', {
180 nick: command.params[1],
181 reason: command.trailing
182 });
183 },
184
185 'RPL_WHOISUSER': function (command) {
186 this.irc_connection.emit('user ' + command.params[1] + ' whoisuser', {
187 nick: command.params[1],
188 ident: command.params[2],
189 host: command.params[3],
190 msg: command.trailing
191 });
192 },
193
194 'RPL_WHOISSERVER': function (command) {
195 this.irc_connection.emit('user ' + command.params[1] + ' whoisserver', {
196 nick: command.params[1],
197 irc_server: command.params[2],
198 server_info: command.trailing
199 });
200 },
201
202 'RPL_WHOISOPERATOR': function (command) {
203 this.irc_connection.emit('user ' + command.params[1] + ' whoisoperator', {
204 nick: command.params[1],
205 msg: command.trailing
206 });
207 },
208
209 'RPL_WHOISCHANNELS': function (command) {
210 this.irc_connection.emit('user ' + command.params[1] + ' whoischannels', {
211 nick: command.params[1],
212 chans: command.trailing
213 });
214 },
215
216 'RPL_WHOISMODES': function (command) {
217 this.irc_connection.emit('user ' + command.params[1] + ' whoismodes', {
218 nick: command.params[1],
219 msg: command.trailing
220 });
221 },
222
223 'RPL_WHOISIDLE': function (command) {
224 this.irc_connection.emit('user ' + command.params[1] + ' whoisidle', {
225 nick: command.params[1],
226 idle: command.params[2],
227 logon: command.params[3] || undefined
228 });
229 },
230
231 'RPL_WHOISREGNICK': function (command) {
232 this.irc_connection.emit('user ' + command.params[1] + ' whoisregnick', {
233 nick: command.params[1],
234 msg: command.trailing
235 });
236 },
237
238 'RPL_WHOISHOST': function (command) {
239 this.irc_connection.emit('user ' + command.params[1] + ' whoishost', {
240 nick: command.params[1],
241 msg: command.trailing
242 });
243 },
244
245 'RPL_WHOISSECURE': function (command) {
246 this.irc_connection.emit('user ' + command.params[1] + ' whoissecure', {
247 nick: command.params[1]
248 });
249 },
250
251 'RPL_WHOISACCOUNT': function (command) {
252 this.irc_connection.emit('user ' + command.params[1] + ' whoisaccount', {
253 nick: command.params[1],
254 account: command.params[2]
255 });
256 },
257
258 'RPL_WHOWASUSER': function (command) {
259 this.irc_connection.emit('user ' + command.params[1] + ' whowas', {
260 nick: command.params[1],
261 ident: command.params[2],
262 host: command.params[3],
263 real_name: command.trailing
264 });
265 },
266
267 'RPL_ENDOFWHOWAS': function (command) {
268 this.irc_connection.emit('user ' + command.params[1] + ' endofwhowas', {
269 nick: command.params[1]
270 });
271 },
272
273 'ERR_WASNOSUCHNICK': function (command) {
274 this.irc_connection.emit('user ' + command.params[1] + ' wasnosucknick', {
275 nick: command.params[1]
276 });
277 },
278
279 'RPL_LISTSTART': function (command) {
280 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_start', {});
281 },
282
283 'RPL_LISTEND': function (command) {
284 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_end', {});
285 },
286
287 'RPL_LIST': function (command) {
288 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' list_channel', {
289 channel: command.params[1],
290 num_users: parseInt(command.params[2], 10),
291 topic: command.trailing
292 });
293 },
294
295 'RPL_MOTD': function (command) {
296 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' motd', {
297 motd: command.trailing + '\n'
298 });
299 },
300
301 'RPL_MOTDSTART': function (command) {
302 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' motd_start', {});
303 },
304
305 'RPL_ENDOFMOTD': function (command) {
306 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' motd_end', {});
307 },
308
309 'RPL_NAMEREPLY': function (command) {
310 var members = command.trailing.split(' ');
311 var member_list = [];
312 var that = this;
313 _.each(members, function (member) {
314 var i = 0,
315 j = 0,
316 modes = [];
317
318 // Make sure we have some prefixes already
319 if (that.irc_connection.options.PREFIX) {
320 for (j = 0; j < that.irc_connection.options.PREFIX.length; j++) {
321 if (member.charAt(i) === that.irc_connection.options.PREFIX[j].symbol) {
322 modes.push(that.irc_connection.options.PREFIX[j].mode);
323 i++;
324 }
325 }
326 }
327
328 member_list.push({nick: member, modes: modes});
329 });
330
331 this.irc_connection.emit('channel ' + command.params[2] + ' userlist', {
332 users: member_list,
333 channel: command.params[2]
334 });
335 },
336
337 'RPL_ENDOFNAMES': function (command) {
338 this.irc_connection.emit('channel ' + command.params[1] + ' userlist_end', {
339 channel: command.params[1]
340 });
341 },
342
343 'RPL_BANLIST': function (command) {
344 this.irc_connection.emit('channel ' + command.params[1] + ' banlist', {
345 channel: command.params[1],
346 banned: command.params[2],
347 banned_by: command.params[3],
348 banned_at: command.params[4]
349 });
350 },
351
352 'RPL_ENDOFBANLIST': function (command) {
353 this.irc_connection.emit('channel ' + command.params[1] + ' banlist_end', {
354 channel: command.params[1]
355 });
356 },
357
358 'RPL_TOPIC': function (command) {
359 this.irc_connection.emit('channel ' + command.params[1] + ' topic', {
360 channel: command.params[1],
361 topic: command.trailing
362 });
363 },
364
365 'RPL_NOTOPIC': function (command) {
366 this.irc_connection.emit('channel ' + command.params[1] + ' topic', {
367 channel: command.params[1],
368 topic: ''
369 });
370 },
371
372 'RPL_TOPICWHOTIME': function (command) {
373 this.irc_connection.emit('channel ' + command.params[1] + ' topicsetby', {
374 nick: command.params[2],
375 channel: command.params[1],
376 when: command.params[3]
377 });
378 },
379
380 'PING': function (command) {
381 this.irc_connection.write('PONG ' + command.trailing);
382 },
383
384 'JOIN': function (command) {
385 var channel;
386 if (typeof command.trailing === 'string' && command.trailing !== '') {
387 channel = command.trailing;
388 } else if (typeof command.params[0] === 'string' && command.params[0] !== '') {
389 channel = command.params[0];
390 }
391
392 this.irc_connection.emit('channel ' + channel + ' join', {
393 nick: command.nick,
394 ident: command.ident,
395 hostname: command.hostname,
396 channel: channel
397 });
398 },
399
400 'PART': function (command) {
401 this.irc_connection.emit('channel ' + command.params[0] + ' part', {
402 nick: command.nick,
403 ident: command.ident,
404 hostname: command.hostname,
405 channel: command.params[0],
406 message: command.trailing
407 });
408 },
409
410 'KICK': function (command) {
411 this.irc_connection.emit('channel ' + command.params[0] + ' kick', {
412 kicked: command.params[1],
413 nick: command.nick,
414 ident: command.ident,
415 hostname: command.hostname,
416 channel: command.params[0],
417 message: command.trailing
418 });
419 },
420
421 'QUIT': function (command) {
422 this.irc_connection.emit('user ' + command.nick + ' quit', {
423 nick: command.nick,
424 ident: command.ident,
425 hostname: command.hostname,
426 message: command.trailing
427 });
428 },
429
430 'NOTICE': function (command) {
431 var namespace;
432
433 if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
434 // It's a CTCP response
435 namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase()) ? 'user' : 'channel';
436 this.irc_connection.emit(namespace + ' ' + command.params[0] + ' ctcp_response', {
437 nick: command.nick,
438 ident: command.ident,
439 hostname: command.hostname,
440 channel: command.params[0],
441 msg: command.trailing.substring(1, command.trailing.length - 1)
442 });
443 } else {
444 namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase() || command.params[0] == '*') ?
445 'user' :
446 'channel';
447
448 this.irc_connection.emit(namespace + ' ' + command.params[0] + ' notice', {
449 from_server: command.prefix ? true : false,
450 nick: command.nick || command.prefix || undefined,
451 ident: command.ident,
452 hostname: command.hostname,
453 target: command.params[0],
454 msg: command.trailing
455 });
456 }
457 },
458
459 'NICK': function (command) {
460 this.irc_connection.emit('user ' + command.nick + ' nick', {
461 nick: command.nick,
462 ident: command.ident,
463 hostname: command.hostname,
464 newnick: command.trailing || command.params[0]
465 });
466 },
467
468 'TOPIC': function (command) {
469 // If we don't have an associated channel, no need to continue
470 if (!command.params[0]) return;
471
472 var channel = command.params[0],
473 topic = command.trailing || '';
474
475 this.irc_connection.emit('channel ' + channel + ' topic', {
476 nick: command.nick,
477 channel: channel,
478 topic: topic
479 });
480 },
481
482 'MODE': function (command) {
483 var chanmodes = this.irc_connection.options.CHANMODES || [],
484 prefixes = this.irc_connection.options.PREFIX || [],
485 always_param = (chanmodes[0] || '').concat((chanmodes[1] || '')),
486 modes = [],
487 has_param, i, j, add, event;
488
489 prefixes = _.reduce(prefixes, function (list, prefix) {
490 list.push(prefix.mode);
491 return list;
492 }, []);
493 always_param = always_param.split('').concat(prefixes);
494
495 has_param = function (mode, add) {
496 if (_.find(always_param, function (m) {
497 return m === mode;
498 })) {
499 return true;
500 } else if (add && _.find((chanmodes[2] || '').split(''), function (m) {
501 return m === mode;
502 })) {
503 return true;
504 } else {
505 return false;
506 }
507 };
508
509 if (!command.params[1]) {
510 command.params[1] = command.trailing;
511 }
512
513 j = 0;
514 for (i = 0; i < command.params[1].length; i++) {
515 switch (command.params[1][i]) {
516 case '+':
517 add = true;
518 break;
519 case '-':
520 add = false;
521 break;
522 default:
523 if (has_param(command.params[1][i], add)) {
524 modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: command.params[2 + j]});
525 j++;
526 } else {
527 modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: null});
528 }
529 }
530 }
531
532 event = (_.contains(this.irc_connection.options.CHANTYPES, command.params[0][0]) ? 'channel ' : 'user ') + command.params[0] + ' mode';
533
534 this.irc_connection.emit(event, {
535 target: command.params[0],
536 nick: command.nick || command.prefix || '',
537 modes: modes
538 });
539 },
540
541 'PRIVMSG': function (command) {
542 var tmp, namespace;
543 if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
544 //CTCP request
545 if (command.trailing.substr(1, 6) === 'ACTION') {
546 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)});
547 } else if (command.trailing.substr(1, 4) === 'KIWI') {
548 tmp = command.trailing.substring(6, command.trailing.length - 1);
549 namespace = tmp.split(' ', 1)[0];
550 this.irc_connection.clientEvent('kiwi', {namespace: namespace, data: tmp.substr(namespace.length + 1)});
551 } else if (command.trailing.substr(1, 7) === 'VERSION') {
552 this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'VERSION KiwiIRC' + String.fromCharCode(1));
553 } else if (command.trailing.substr(1, 6) === 'SOURCE') {
554 this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'SOURCE http://www.kiwiirc.com/' + String.fromCharCode(1));
555 } else if (command.trailing.substr(1, 10) === 'CLIENTINFO') {
556 this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'CLIENTINFO SOURCE VERSION TIME' + String.fromCharCode(1));
557 } else {
558 namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase()) ? 'user' : 'channel';
559 this.irc_connection.emit(namespace + ' ' + command.nick + ' ctcp_request', {
560 nick: command.nick,
561 ident: command.ident,
562 hostname: command.hostname,
563 target: command.params[0],
564 type: (command.trailing.substring(1, command.trailing.length - 1).split(' ') || [null])[0],
565 msg: command.trailing.substring(1, command.trailing.length - 1)
566 });
567 }
568 } else {
569 // A message to a user (private message) or to a channel?
570 namespace = (command.params[0].toLowerCase() == this.irc_connection.nick.toLowerCase()) ? 'user ' + command.nick : 'channel ' + command.params[0];
571 this.irc_connection.emit(namespace + ' privmsg', {
572 nick: command.nick,
573 ident: command.ident,
574 hostname: command.hostname,
575 channel: command.params[0],
576 msg: command.trailing
577 });
578 }
579 },
580
581 'CAP': function (command) {
582 // TODO: capability modifiers
583 // i.e. - for disable, ~ for requires ACK, = for sticky
584 var capabilities = command.trailing.replace(/[\-~=]/, '').split(' ');
585 var request;
586
587 // Which capabilities we want to enable
588 var want = ['multi-prefix', 'away-notify'];
589
590 if (this.irc_connection.password) {
591 want.push('sasl');
592 }
593
594 switch (command.params[1]) {
595 case 'LS':
596 // Compute which of the available capabilities we want and request them
597 request = _.intersection(capabilities, want);
598 if (request.length > 0) {
599 this.irc_connection.cap.requested = request;
600 this.irc_connection.write('CAP REQ :' + request.join(' '));
601 } else {
602 this.irc_connection.write('CAP END');
603 this.irc_connection.cap_negotation = false;
604 }
605 break;
606 case 'ACK':
607 if (capabilities.length > 0) {
608 // Update list of enabled capabilities
609 this.irc_connection.cap.enabled = capabilities;
610 // Update list of capabilities we would like to have but that aren't enabled
611 this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
612 }
613 if (this.irc_connection.cap.enabled.length > 0) {
614 if (_.contains(this.irc_connection.cap.enabled, 'sasl')) {
615 this.irc_connection.sasl = true;
616 this.irc_connection.write('AUTHENTICATE PLAIN');
617 } else {
618 this.irc_connection.write('CAP END');
619 this.irc_connection.cap_negotation = false;
620 }
621 }
622 break;
623 case 'NAK':
624 if (capabilities.length > 0) {
625 this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
626 }
627 if (this.irc_connection.cap.requested.length > 0) {
628 this.irc_connection.write('CAP END');
629 this.irc_connection.cap_negotation = false;
630 }
631 break;
632 case 'LIST':
633 // should we do anything here?
634 break;
635 }
636 },
637
638 'AUTHENTICATE': function (command) {
639 var b = new Buffer(this.irc_connection.nick + "\0" + this.irc_connection.nick + "\0" + this.irc_connection.password, 'utf8');
640 var b64 = b.toString('base64');
641 if (command.params[0] === '+') {
642 while (b64.length >= 400) {
643 this.irc_connection.write('AUTHENTICATE ' + b64.slice(0, 399));
644 b64 = b64.slice(399);
645 }
646 if (b64.length > 0) {
647 this.irc_connection.write('AUTHENTICATE ' + b64);
648 } else {
649 this.irc_connection.write('AUTHENTICATE +');
650 }
651 } else {
652 this.irc_connection.write('CAP END');
653 this.irc_connection.cap_negotation = false;
654 }
655 },
656
657 'AWAY': function (command) {
658 this.irc_connection.emit('user ' + command.nick + ' away', {
659 nick: command.nick,
660 msg: command.trailing
661 });
662 },
663
664 'RPL_SASLAUTHENTICATED': function (command) {
665 this.irc_connection.write('CAP END');
666 this.irc_connection.cap_negotation = false;
667 this.irc_connection.sasl = true;
668 },
669
670 'RPL_SASLLOGGEDIN': function (command) {
671 if (this.irc_connection.cap_negotation === false) {
672 this.irc_connection.write('CAP END');
673 }
674 },
675
676 'ERR_SASLNOTAUTHORISED': function (command) {
677 this.irc_connection.write('CAP END');
678 this.irc_connection.cap_negotation = false;
679 },
680
681 'ERR_SASLABORTED': function (command) {
682 this.irc_connection.write('CAP END');
683 this.irc_connection.cap_negotation = false;
684 },
685
686 'ERR_SASLALREADYAUTHED': function (command) {
687 // noop
688 },
689
690 'ERROR': function (command) {
691 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' error', {
692 reason: command.trailing
693 });
694 },
695 ERR_PASSWDMISMATCH: function (command) {
696 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' password_mismatch', {});
697 },
698
699 ERR_LINKCHANNEL: function (command) {
700 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' channel_redirect', {
701 from: command.params[1],
702 to: command.params[2]
703 });
704 },
705
706 ERR_NOSUCHNICK: function (command) {
707 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' no_such_nick', {
708 nick: command.params[1],
709 reason: command.trailing
710 });
711 },
712
713 ERR_CANNOTSENDTOCHAN: function (command) {
714 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' cannot_send_to_chan', {
715 channel: command.params[1],
716 reason: command.trailing
717 });
718 },
719
720 ERR_TOOMANYCHANNELS: function (command) {
721 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' too_many_channels', {
722 channel: command.params[1],
723 reason: command.trailing
724 });
725 },
726
727 ERR_USERNOTINCHANNEL: function (command) {
728 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' user_not_in_channel', {
729 nick: command.params[0],
730 channel: command.params[1],
731 reason: command.trailing
732 });
733 },
734
735 ERR_NOTONCHANNEL: function (command) {
736 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' not_on_channel', {
737 channel: command.params[1],
738 reason: command.trailing
739 });
740 },
741
742 ERR_USERONCHANNEL: function (command) {
743 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' user_on_channel', {
744 nick: command.params[1],
745 channel: command.params[2]
746 });
747 },
748
749 ERR_CHANNELISFULL: function (command) {
750 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' channel_is_full', {
751 channel: command.params[1],
752 reason: command.trailing
753 });
754 },
755
756 ERR_INVITEONLYCHAN: function (command) {
757 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' invite_only_channel', {
758 channel: command.params[1],
759 reason: command.trailing
760 });
761 },
762
763 ERR_BANNEDFROMCHAN: function (command) {
764 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' banned_from_channel', {
765 channel: command.params[1],
766 reason: command.trailing
767 });
768 },
769
770 ERR_BADCHANNELKEY: function (command) {
771 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' bad_channel_key', {
772 channel: command.params[1],
773 reason: command.trailing
774 });
775 },
776
777 ERR_CHANOPRIVSNEEDED: function (command) {
778 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' chanop_privs_needed', {
779 channel: command.params[1],
780 reason: command.trailing
781 });
782 },
783
784 ERR_NICKNAMEINUSE: function (command) {
785 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' nickname_in_use', {
786 nick: command.params[1],
787 reason: command.trailing
788 });
789 },
790
791 ERR_ERRONEUSNICKNAME: function(command) {
792 this.irc_connection.emit('server ' + this.irc_connection.irc_host.hostname + ' erroneus_nickname', {
793 nick: command.params[1],
794 reason: command.trailing
795 });
796 },
797
798 ERR_NOTREGISTERED: function (command) {
799 },
800
801 RPL_MAPMORE: function (command) {
802 var params = _.clone(command.params);
803 params.shift();
804 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
805 },
806
807 RPL_MAPEND: function (command) {
808 var params = _.clone(command.params);
809 params.shift();
810 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
811 },
812
813 RPL_LINKS: function (command) {
814 var params = _.clone(command.params);
815 params.shift();
816 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
817 },
818
819 RPL_ENDOFLINKS: function (command) {
820 var params = _.clone(command.params);
821 params.shift();
822 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
823 },
824
825 ERR_UNKNOWNCOMMAND: function (command) {
826 var params = _.clone(command.params);
827 params.shift();
828 genericNotice.call(this, command, '`' + params.join(', ') + '` ' + command.trailing);
829 },
830
831 ERR_NOMOTD: function (command) {
832 var params = _.clone(command.params);
833 params.shift();
834 genericNotice.call(this, command, command.trailing);
835 },
836
837 ERR_NOPRIVILEGES: function (command) {
838 var params = _.clone(command.params);
839 params.shift();
840 genericNotice.call(this, command, command.trailing);
841 },
842
843 RPL_STATSCONN: function (command) {
844 var params = _.clone(command.params);
845 params.shift();
846 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
847 },
848
849 RPL_LUSERCLIENT: function (command) {
850 var params = _.clone(command.params);
851 params.shift();
852 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
853 },
854
855 RPL_LUSEROP: function (command) {
856 var params = _.clone(command.params);
857 params.shift();
858 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
859 },
860
861 RPL_LUSERUNKNOWN: function (command) {
862 var params = _.clone(command.params);
863 params.shift();
864 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
865 },
866
867 RPL_LUSERCHANNELS: function (command) {
868 var params = _.clone(command.params);
869 params.shift();
870 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
871 },
872
873 RPL_LUSERME: function (command) {
874 var params = _.clone(command.params);
875 params.shift();
876 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
877 },
878
879 RPL_LOCALUSERS: function (command) {
880 var params = _.clone(command.params);
881 params.shift();
882 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
883 },
884
885 RPL_GLOBALUSERS: function (command) {
886 var params = _.clone(command.params);
887 params.shift();
888 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
889 }
890 };
891
892
893
894
895 function genericNotice (command, msg, is_error) {
896 // Default to being an error
897 if (typeof is_error !== 'boolean')
898 is_error = true;
899
900 this.irc_connection.clientEvent('notice', {
901 from_server: true,
902 nick: command.prefix,
903 ident: '',
904 hostname: '',
905 target: command.params[0],
906 msg: msg,
907 numeric: parseInt(command.command, 10)
908 });
909 }