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