IrcChannel + IrcCommands topic event
[KiwiIRC.git] / server / irc / commands.js
... / ...
CommitLineData
1var _ = require('lodash');
2
3var 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
58var IrcCommands = function (irc_connection, con_num, client) {
59 this.irc_connection = irc_connection;
60 this.con_num = con_num;
61 this.client = client;
62};
63module.exports = IrcCommands;
64
65IrcCommands.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
79IrcCommands.prototype.dispose = function () {
80 this.removeAllListeners();
81};
82
83
84
85var 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
601function 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}