IrcCommands + IrcChannel
[KiwiIRC.git] / server / irc / commands.js
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.client.sendIrcCommand('topic', {server: this.con_num, nick: command.nick, channel: channel, topic: topic});
322 },
323 'MODE': function (command) {
324 var chanmodes = this.irc_connection.options.CHANMODES || [],
325 prefixes = this.irc_connection.options.PREFIX || [],
326 always_param = (chanmodes[0] || '').concat((chanmodes[1] || '')),
327 modes = [],
328 has_param, i, j, add;
329
330 prefixes = _.reduce(prefixes, function (list, prefix) {
331 list.push(prefix.mode);
332 return list;
333 }, []);
334 always_param = always_param.split('').concat(prefixes);
335
336 has_param = function (mode, add) {
337 if (_.find(always_param, function (m) {
338 return m === mode;
339 })) {
340 return true;
341 } else if (add && _.find((chanmodes[2] || '').split(''), function (m) {
342 return m === mode;
343 })) {
344 return true;
345 } else {
346 return false;
347 }
348 };
349
350 if (!command.params[1]) {
351 command.params[1] = command.trailing;
352 }
353 j = 0;
354 for (i = 0; i < command.params[1].length; i++) {
355 switch (command.params[1][i]) {
356 case '+':
357 add = true;
358 break;
359 case '-':
360 add = false;
361 break;
362 default:
363 if (has_param(command.params[1][i], add)) {
364 modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: command.params[2 + j]});
365 j++;
366 } else {
367 modes.push({mode: (add ? '+' : '-') + command.params[1][i], param: null});
368 }
369 }
370 }
371
372 this.client.sendIrcCommand('mode', {
373 server: this.con_num,
374 target: command.params[0],
375 nick: command.nick || command.prefix || '',
376 modes: modes
377 });
378 },
379 'PRIVMSG': function (command) {
380 var tmp, namespace;
381 if ((command.trailing.charAt(0) === String.fromCharCode(1)) && (command.trailing.charAt(command.trailing.length - 1) === String.fromCharCode(1))) {
382 //CTCP request
383 if (command.trailing.substr(1, 6) === 'ACTION') {
384 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)});
385 } else if (command.trailing.substr(1, 4) === 'KIWI') {
386 tmp = command.trailing.substr(6, command.trailing.length - 2);
387 namespace = tmp.split(' ', 1)[0];
388 this.client.sendIrcCommand('kiwi', {server: this.con_num, namespace: namespace, data: tmp.substr(namespace.length + 1)});
389 } else if (command.trailing.substr(1, 7) === 'VERSION') {
390 this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'VERSION KiwiIRC' + String.fromCharCode(1));
391 } else if (command.trailing.substr(1, 6) === 'SOURCE') {
392 this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'SOURCE http://www.kiwiirc.com/' + String.fromCharCode(1));
393 } else if (command.trailing.substr(1, 10) === 'CLIENTINFO') {
394 this.irc_connection.write('NOTICE ' + command.nick + ' :' + String.fromCharCode(1) + 'CLIENTINFO SOURCE VERSION TIME' + String.fromCharCode(1));
395 } else {
396 namespace = (command.target == this.irc_connection.nick) ? 'user' : 'channel';
397 this.irc_connection.emit(namespace + ':' + command.nick + ':ctcp_request', {
398 nick: command.nick,
399 ident: command.ident,
400 hostname: command.hostname,
401 target: command.params[0],
402 type: (command.trailing.substr(1, command.trailing.length - 2).split(' ') || [null])[0],
403 msg: command.trailing.substr(1, command.trailing.length - 2)
404 });
405 }
406 } else {
407 // A message to a user (private message) or to a channel?
408 namespace = (command.target == this.irc_connection.nick) ? 'user' : 'channel';
409 this.irc_connection.emit(namespace + ':' + command.nick + ':privmsg', {
410 nick: command.nick,
411 ident: command.ident,
412 hostname: command.hostname,
413 channel: command.params[0],
414 msg: command.trailing
415 );
416 }
417 },
418 'CAP': function (command) {
419 // TODO: capability modifiers
420 // i.e. - for disable, ~ for requires ACK, = for sticky
421 var capabilities = command.trailing.replace(/[\-~=]/, '').split(' ');
422 var request;
423 var want = ['multi-prefix', 'away-notify'];
424
425 if (this.irc_connection.password) {
426 want.push('sasl');
427 }
428
429 switch (command.params[1]) {
430 case 'LS':
431 request = _.intersection(capabilities, want);
432 if (request.length > 0) {
433 this.irc_connection.cap.requested = request;
434 this.irc_connection.write('CAP REQ :' + request.join(' '));
435 } else {
436 this.irc_connection.write('CAP END');
437 this.irc_connection.cap_negotation = false;
438 }
439 break;
440 case 'ACK':
441 if (capabilities.length > 0) {
442 this.irc_connection.cap.enabled = capabilities;
443 this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
444 }
445 if (this.irc_connection.cap.requested.length > 0) {
446 if (_.contains(this.irc_connection.cap.enabled, 'sasl')) {
447 this.irc_connection.sasl = true;
448 this.irc_connection.write('AUTHENTICATE PLAIN');
449 } else {
450 this.irc_connection.write('CAP END');
451 this.irc_connection.cap_negotation = false;
452 }
453 }
454 break;
455 case 'NAK':
456 if (capabilities.length > 0) {
457 this.irc_connection.cap.requested = _.difference(this.irc_connection.cap.requested, capabilities);
458 }
459 if (this.irc_connection.cap.requested.length > 0) {
460 this.irc_connection.write('CAP END');
461 this.irc_connection.cap_negotation = false;
462 }
463 break;
464 case 'LIST':
465 // should we do anything here?
466 break;
467 }
468 },
469 'AUTHENTICATE': function (command) {
470 var b = new Buffer(this.irc_connection.nick + "\0" + this.irc_connection.nick + "\0" + this.irc_connection.password, 'utf8');
471 var b64 = b.toString('base64');
472 if (command.params[0] === '+') {
473 while (b64.length >= 400) {
474 this.irc_connection.write('AUTHENTICATE ' + b64.slice(0, 399));
475 b64 = b64.slice(399);
476 }
477 if (b64.length > 0) {
478 this.irc_connection.write('AUTHENTICATE ' + b64);
479 } else {
480 this.irc_connection.write('AUTHENTICATE +');
481 }
482 } else {
483 this.irc_connection.write('CAP END');
484 this.irc_connection.cap_negotation = false;
485 }
486 },
487 'AWAY': function (command) {
488 this.client.sendIrcCommand('away', {server: this.con_num, nick: command.nick, msg: command.trailing});
489 },
490 'RPL_SASLAUTHENTICATED': function (command) {
491 this.irc_connection.write('CAP END');
492 this.irc_connection.cap_negotation = false;
493 this.irc_connection.sasl = true;
494 },
495 'RPL_SASLLOGGEDIN': function (command) {
496 if (this.irc_connection.cap_negotation === false) {
497 this.irc_connection.write('CAP END');
498 }
499 },
500 'ERR_SASLNOTAUTHORISED': function (command) {
501 this.irc_connection.write('CAP END');
502 this.irc_connection.cap_negotation = false;
503 },
504 'ERR_SASLABORTED': function (command) {
505 this.irc_connection.write('CAP END');
506 this.irc_connection.cap_negotation = false;
507 },
508 'ERR_SASLALREADYAUTHED': function (command) {
509 // noop
510 },
511 'ERROR': function (command) {
512 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'error', reason: command.trailing});
513 },
514 ERR_LINKCHANNEL: function (command) {
515 this.client.sendIrcCommand('channel_redirect', {server: this.con_num, from: command.params[1], to: command.params[2]});
516 },
517 ERR_NOSUCHNICK: function (command) {
518 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'no_such_nick', nick: command.params[1], reason: command.trailing});
519 },
520 ERR_CANNOTSENDTOCHAN: function (command) {
521 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'cannot_send_to_chan', channel: command.params[1], reason: command.trailing});
522 },
523 ERR_TOOMANYCHANNELS: function (command) {
524 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'too_many_channels', channel: command.params[1], reason: command.trailing});
525 },
526 ERR_USERNOTINCHANNEL: function (command) {
527 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});
528 },
529 ERR_NOTONCHANNEL: function (command) {
530 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'not_on_channel', channel: command.params[1], reason: command.trailing});
531 },
532 ERR_CHANNELISFULL: function (command) {
533 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'channel_is_full', channel: command.params[1], reason: command.trailing});
534 },
535 ERR_INVITEONLYCHAN: function (command) {
536 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'invite_only_channel', channel: command.params[1], reason: command.trailing});
537 },
538 ERR_BANNEDFROMCHAN: function (command) {
539 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'banned_from_channel', channel: command.params[1], reason: command.trailing});
540 },
541 ERR_BADCHANNELKEY: function (command) {
542 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'bad_channel_key', channel: command.params[1], reason: command.trailing});
543 },
544 ERR_CHANOPRIVSNEEDED: function (command) {
545 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'chanop_privs_needed', channel: command.params[1], reason: command.trailing});
546 },
547 ERR_NICKNAMEINUSE: function (command) {
548 this.client.sendIrcCommand('irc_error', {server: this.con_num, error: 'nickname_in_use', nick: command.params[1], reason: command.trailing});
549 },
550 ERR_NOTREGISTERED: function (command) {
551 },
552
553 RPL_MAPMORE: function (command) {
554 var params = _.clone(command.params);
555 params.shift();
556 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
557 },
558 RPL_MAPEND: function (command) {
559 var params = _.clone(command.params);
560 params.shift();
561 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
562 },
563
564 RPL_LINKS: function (command) {
565 var params = _.clone(command.params);
566 params.shift();
567 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
568 },
569 RPL_ENDOFLINKS: function (command) {
570 var params = _.clone(command.params);
571 params.shift();
572 genericNotice.call(this, command, params.join(', ') + ' ' + command.trailing);
573 },
574
575 ERR_UNKNOWNCOMMAND: function (command) {
576 var params = _.clone(command.params);
577 params.shift();
578 genericNotice.call(this, command, '`' + params.join(', ') + '` ' + command.trailing);
579 },
580
581 ERR_NOMOTD: function (command) {
582 var params = _.clone(command.params);
583 params.shift();
584 genericNotice.call(this, command, command.trailing);
585 },
586
587 ERR_NOPRIVILEGES: function (command) {
588 var params = _.clone(command.params);
589 params.shift();
590 genericNotice.call(this, command, command.trailing);
591 }
592 };
593
594
595
596
597 function genericNotice (command, msg, is_error) {
598 // Default to being an error
599 if (typeof is_error !== 'boolean')
600 is_error = true;
601
602 this.client.sendIrcCommand('notice', {
603 server: this.con_num,
604 nick: command.prefix,
605 ident: '',
606 hostname: '',
607 target: command.params[0],
608 msg: msg,
609 numeric: parseInt(command.command, 10)
610 });
611 }