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