]> jfr.im git - irc/quakenet/qwebirc.git/blob - js/irc/baseircclient.js
Merge pull request #402 from retropc/reqs
[irc/quakenet/qwebirc.git] / js / irc / baseircclient.js
1 qwebirc.irc.PMODE_LIST = 0;
2 qwebirc.irc.PMODE_SET_UNSET = 1;
3 qwebirc.irc.PMODE_SET_ONLY = 2;
4 qwebirc.irc.PMODE_REGULAR_MODE = 3;
5
6 qwebirc.irc.RegisteredCTCPs = new QHash({
7 "VERSION": function(x) {
8 return "qwebirc v" + qwebirc.VERSION + ", copyright (C) 2008-2018 Chris Porter and the qwebirc project -- transport: " + this.connection.transportStatus + " -- " + qwebirc.util.browserVersion();
9 },
10 "USERINFO": function(x) { return "qwebirc"; },
11 "TIME": function(x) { return qwebirc.irc.IRCDate(new Date()); },
12 "PING": function(x) { return x; },
13 "CLIENTINFO": function(x) { return "PING VERSION TIME USERINFO CLIENTINFO WEBSITE"; },
14 "WEBSITE": function(x) { return window == window.top ? "direct" : document.referrer; }
15 });
16
17 qwebirc.irc.BaseIRCClient = new Class({
18 Implements: [Options, Events],
19 options: {
20 nickname: "qwebirc"
21 },
22 initialize: function(options) {
23 this.setOptions(options);
24
25 this.toIRCLower = qwebirc.irc.RFC1459toIRCLower;
26
27 this.nickname = this.options.nickname;
28 this.lowerNickname = this.toIRCLower(this.nickname);
29
30 this.__signedOn = false;
31 this.pmodes = new QHash({b: qwebirc.irc.PMODE_LIST, l: qwebirc.irc.PMODE_SET_ONLY, k: qwebirc.irc.PMODE_SET_UNSET, o: qwebirc.irc.PMODE_SET_UNSET, v: qwebirc.irc.PMODE_SET_UNSET});
32 this.channels = new QSet();
33 this.chanPrefixes = new QSet("#", "&");
34 this.nextctcp = 0;
35
36 this.connection = new qwebirc.irc.IRCConnection({
37 initialNickname: this.nickname,
38 onRecv: this.dispatch.bind(this),
39 serverPassword: this.options.serverPassword
40 });
41
42 this.send = this.connection.send.bind(this.connection);
43 this.disconnect = this.connection.disconnect.bind(this.connection);
44
45 this.setupGenericErrors();
46 },
47 connect: function() {
48 this.connection.connect.apply(this.connection);
49 },
50 dispatch: function(data) {
51 var message = data[0];
52 if(message == "connect") {
53 this.connected();
54 } else if(message == "disconnect") {
55 if(data.length == 0) {
56 this.disconnected("No error!");
57 } else {
58 this.disconnected(data[1]);
59 }
60 this.disconnect();
61 } else if(message == "c") {
62 var command = data[1].toUpperCase();
63
64 var prefix = data[2];
65 var sl = data[3];
66 var n = qwebirc.irc.Numerics.get(command);
67
68 var x = n;
69 if(!n)
70 n = command;
71
72 var o = this["irc_" + n];
73
74 if(o) {
75 var r = o.run([prefix, sl], this);
76 if(!r)
77 this.rawNumeric(command, prefix, sl);
78 } else {
79 this.rawNumeric(command, prefix, sl);
80 }
81 }
82 },
83 isChannel: function(target) {
84 var c = target.charAt(0);
85 return this.chanPrefixes.contains(c);
86 },
87 supported: function(key, value) {
88 if(key == "CASEMAPPING") {
89 if(value == "ascii") {
90 this.toIRCLower = qwebirc.irc.ASCIItoIRCLower;
91 } else if(value == "rfc1459") {
92 /* IGNORE */
93 } else {
94 /* TODO: warn */
95 }
96 this.lowerNickname = this.toIRCLower(this.nickname);
97 } else if(key == "CHANMODES") {
98 var smodes = value.split(",");
99 for(var i=0;i<smodes.length;i++)
100 for(var j=0;j<smodes[i].length;j++)
101 this.pmodes.put(smodes[i].charAt(j), i);
102 } else if(key == "CHANTYPES") {
103 this.chanPrefixes = new QSet();
104 for(var i=0;i<value.length;i++)
105 this.chanPrefixes.add(value.charAt(i));
106 } else if(key == "PREFIX") {
107 var l = (value.length - 2) / 2;
108
109 var modeprefixes = value.substr(1, l).split("");
110 modeprefixes.each(function(modeprefix) {
111 this.pmodes.put(modeprefix, qwebirc.irc.PMODE_SET_UNSET);
112 }, this);
113 }
114 },
115 irc_RPL_WELCOME: function(prefix, params) {
116 this.nickname = params[0];
117 this.lowerNickname = this.toIRCLower(this.nickname);
118 this.__signedOn = true;
119 this.signedOn(this.nickname);
120 },
121 irc_ERR_NICKNAMEINUSE: function(prefix, params) {
122 this.genericError(params[1], params.indexFromEnd(-1).replace("in use.", "in use"));
123
124 if(this.__signedOn)
125 return true;
126
127 var newnick = params[1] + "_";
128 if(newnick == this.lastnick)
129 newnick = "qwebirc" + Math.floor(Math.random() * 1024 * 1024);
130
131 this.send("NICK " + newnick);
132 this.lastnick = newnick;
133 return true;
134 },
135 irc_NICK: function(prefix, params) {
136 var user = prefix;
137 var oldnick = user.hostToNick();
138 var newnick = params[0];
139
140 if(this.nickname == oldnick) {
141 this.nickname = newnick;
142 this.lowerNickname = this.toIRCLower(this.nickname);
143 }
144
145 this.nickChanged(user, newnick);
146
147 return true;
148 },
149 irc_QUIT: function(prefix, params) {
150 var user = prefix;
151
152 var message = params.indexFromEnd(-1);
153
154 this.userQuit(user, message);
155
156 return true;
157 },
158 irc_PART: function(prefix, params) {
159 var user = prefix;
160 var channel = params[0];
161 var message = params[1];
162
163 var nick = user.hostToNick();
164
165 if((nick == this.nickname) && this.__getChannel(channel))
166 this.__killChannel(channel);
167
168 this.userPart(user, channel, message);
169
170 return true;
171 },
172 __getChannel: function(name) {
173 return this.channels.contains(this.toIRCLower(name));
174 },
175 __killChannel: function(name) {
176 this.channels.remove(this.toIRCLower(name));
177 },
178 __nowOnChannel: function(name) {
179 this.channels.add(this.toIRCLower(name));
180 },
181 irc_KICK: function(prefix, params) {
182 var kicker = prefix;
183 var channel = params[0];
184 var kickee = params[1];
185 var message = params[2];
186
187 if((kickee == this.nickname) && this.__getChannel(channel))
188 this.__killChannel(channel);
189
190 this.userKicked(kicker, channel, kickee, message);
191
192 return true;
193 },
194 irc_PING: function(prefix, params) {
195 this.send("PONG :" + params.indexFromEnd(-1));
196
197 return true;
198 },
199 irc_JOIN: function(prefix, params) {
200 var channel = params[0];
201 var user = prefix;
202 var nick = user.hostToNick();
203
204 if(nick == this.nickname)
205 this.__nowOnChannel(channel);
206
207 this.userJoined(user, channel);
208
209 return true;
210 },
211 irc_TOPIC: function(prefix, params) {
212 var user = prefix;
213 var channel = params[0];
214 var topic = params.indexFromEnd(-1);
215
216 this.channelTopic(user, channel, topic);
217
218 return true;
219 },
220 processCTCP: function(message) {
221 if(message.charAt(0) != "\x01")
222 return;
223
224 if(message.charAt(message.length - 1) == "\x01") {
225 message = message.substr(1, message.length - 2);
226 } else {
227 message = message.substr(1);
228 }
229 return message.splitMax(" ", 2);
230 },
231 irc_PRIVMSG: function(prefix, params) {
232 var user = prefix;
233 var target = params[0];
234 var message = params.indexFromEnd(-1);
235
236 var ctcp = this.processCTCP(message);
237 if(ctcp) {
238 var type = ctcp[0].toUpperCase();
239
240 var replyfn = qwebirc.irc.RegisteredCTCPs.get(type);
241 if(replyfn) {
242 var t = new Date().getTime() / 1000;
243 if(t > this.nextctcp) {
244 this.send("NOTICE " + user.hostToNick() + " :\x01" + type + " " + replyfn.call(this, ctcp[1]) + "\x01");
245 this.nextctcp = t + 10;
246 }
247 }
248
249 if(target == this.nickname) {
250 this.userCTCP(user, type, ctcp[1]);
251 } else {
252 this.channelCTCP(user, target, type, ctcp[1]);
253 }
254 } else {
255 if(target == this.nickname) {
256 this.userPrivmsg(user, message);
257 } else {
258 this.channelPrivmsg(user, target, message);
259 }
260 }
261
262 return true;
263 },
264 irc_NOTICE: function(prefix, params) {
265 var user = prefix;
266 var target = params[0];
267 var message = params.indexFromEnd(-1);
268
269 if((user == "") || (user.indexOf("!") == -1)) {
270 this.serverNotice(user, message);
271 } else if(target == this.nickname) {
272 var ctcp = this.processCTCP(message);
273 if(ctcp) {
274 this.userCTCPReply(user, ctcp[0], ctcp[1]);
275 } else {
276 this.userNotice(user, message);
277 }
278 } else {
279 this.channelNotice(user, target, message);
280 }
281
282 return true;
283 },
284 irc_INVITE: function(prefix, params) {
285 var user = prefix;
286 var channel = params.indexFromEnd(-1);
287
288 this.userInvite(user, channel);
289
290 return true;
291 },
292 irc_ERROR: function(prefix, params) {
293 var message = params.indexFromEnd(-1);
294
295 this.serverError(message);
296
297 return true;
298 },
299 irc_MODE: function(prefix, params) {
300 var user = prefix;
301 var target = params[0];
302 var args = params.slice(1);
303
304 if(target == this.nickname) {
305 this.userMode(args);
306 } else {
307 var modes = args[0].split("");
308 var xargs = args.slice(1);
309
310 var data = []
311 var carg = 0;
312 var pos = 0;
313 var cmode = "+";
314
315 modes.each(function(mode) {
316 if((mode == "+") || (mode == "-")) {
317 cmode = mode;
318 return;
319 }
320
321 var d;
322 var pmode = this.pmodes.get(mode);
323 if(pmode == qwebirc.irc.PMODE_LIST || pmode == qwebirc.irc.PMODE_SET_UNSET || (cmode == "+" && pmode == qwebirc.irc.PMODE_SET_ONLY)) {
324 d = [cmode, mode, xargs[carg++]]
325 } else {
326 d = [cmode, mode]
327 }
328
329 data.push(d);
330 }, this);
331
332 this.channelMode(user, target, data, args);
333 }
334
335 return true;
336 },
337 irc_RPL_ISUPPORT: function(prefix, params) {
338 var supported = params.slice(1, -1);
339
340 var items = new QSet();
341 for(var i=0;i<supported.length;i++) {
342 var l = supported[i].splitMax("=", 2);
343 items.add(l[0]);
344 }
345
346 if(items.contains("CHANMODES") && items.contains("PREFIX")) /* nasty hack */
347 this.pmodes = new QHash();
348
349 for(var i=0;i<supported.length;i++) {
350 var l = supported[i].splitMax("=", 2);
351 this.supported(l[0], l[1]);
352 }
353 },
354 irc_RPL_NAMREPLY: function(prefix, params) {
355 var channel = params[2];
356 var names = params[3];
357
358 this.channelNames(channel, names.split(" "));
359
360 return true;
361 },
362 irc_RPL_ENDOFNAMES: function(prefix, params) {
363 var channel = params[1];
364
365 this.channelNames(channel, []);
366 return true;
367 },
368 irc_RPL_NOTOPIC: function(prefix, params) {
369 var channel = params[1];
370
371 if(this.__getChannel(channel)) {
372 this.initialTopic(channel, "");
373 return true;
374 }
375 },
376 irc_RPL_TOPIC: function(prefix, params) {
377 var channel = params[1];
378 var topic = params.indexFromEnd(-1);
379
380 if(this.__getChannel(channel)) {
381 this.initialTopic(channel, topic);
382 return true;
383 }
384 },
385 irc_RPL_TOPICWHOTIME: function(prefix, params) {
386 return true;
387 },
388 irc_RPL_WHOISUSER: function(prefix, params) {
389 var nick = params[1];
390 this.whoisNick = nick;
391
392 return this.whois(nick, "user", {ident: params[2], hostname: params[3], realname: params.indexFromEnd(-1)});
393 },
394 irc_RPL_WHOISSERVER: function(prefix, params) {
395 var nick = params[1];
396 var server = params[2];
397 var serverdesc = params.indexFromEnd(-1);
398
399 return this.whois(nick, "server", {server: params[2], serverdesc: params.indexFromEnd(-1)});
400 },
401 irc_RPL_WHOISOPERATOR: function(prefix, params) {
402 var nick = params[1];
403 var text = params.indexFromEnd(-1);
404
405 return this.whois(nick, "oper", {opertext: params.indexFromEnd(-1)});
406 },
407 irc_RPL_WHOISIDLE: function(prefix, params) {
408 var nick = params[1];
409
410 return this.whois(nick, "idle", {idle: params[2], connected: params[3]});
411 },
412 irc_RPL_WHOISCHANNELS: function(prefix, params) {
413 var nick = params[1];
414
415 return this.whois(nick, "channels", {channels: params.indexFromEnd(-1)});
416 },
417 irc_RPL_WHOISACCOUNT: function(prefix, params) {
418 var nick = params[1];
419
420 return this.whois(nick, "account", {account: params[2]});
421 },
422 irc_RPL_WHOISACTUALLY: function(prefix, params) {
423 var nick = params[1];
424
425 return this.whois(nick, "actually", {hostmask: params[2], ip: params[3]});
426 },
427 irc_RPL_WHOISOPERNAME: function(prefix, params) {
428 var nick = params[1];
429 var opername = params[2];
430
431 return this.whois(nick, "opername", {opername: params[2]});
432 },
433 irc_RPL_WHOISGENERICTEXT: function(prefix, params) {
434 var nick = params[1];
435 var text = params.indexFromEnd(-1);
436
437 return this.whois(nick, "generictext", {text: text});
438 },
439 irc_RPL_WHOISWEBIRC: function(prefix, params) {
440 var nick = params[1];
441 var text = params.indexFromEnd(-1);
442
443 return this.whois(nick, "generictext", {text: text});
444 },
445 irc_RPL_WHOISSECURE: function(prefix, params) {
446 var nick = params[1];
447 var text = params.indexFromEnd(-1);
448
449 return this.whois(nick, "generictext", {text: text});
450 },
451 irc_RPL_ENDOFWHOIS: function(prefix, params) {
452 var nick = params[1];
453 var text = params.indexFromEnd(-1);
454 this.whoisNick = null;
455
456 return this.whois(nick, "end", {});
457 },
458 irc_genericError: function(prefix, params) {
459 var target = params[1];
460 var message = params.indexFromEnd(-1);
461
462 this.genericError(target, message);
463 return true;
464 },
465 irc_genericQueryError: function(prefix, params) {
466 var target = params[1];
467 var message = params.indexFromEnd(-1);
468
469 this.genericQueryError(target, message);
470 return true;
471 },
472 setupGenericErrors: function() {
473 this.irc_ERR_CHANOPPRIVSNEEDED = this.irc_ERR_CANNOTSENDTOCHAN = this.irc_genericError;
474 this.irc_ERR_NOSUCHNICK = this.irc_genericQueryError;
475 return true;
476 },
477 irc_RPL_AWAY: function(prefix, params) {
478 var nick = params[1];
479 var text = params.indexFromEnd(-1);
480
481 if(this.whoisNick && (this.whoisNick == nick))
482 return this.whois(nick, "away", {"away": text});
483
484 this.awayMessage(nick, text);
485 return true;
486 },
487 irc_RPL_NOWAWAY: function(prefix, params) {
488 this.awayStatus(true, params.indexFromEnd(-1));
489 return true;
490 },
491 irc_RPL_UNAWAY: function(prefix, params) {
492 this.awayStatus(false, params.indexFromEnd(-1));
493 return true;
494 },
495 irc_WALLOPS: function(prefix, params) {
496 var user = prefix;
497 var text = params.indexFromEnd(-1);
498
499 this.wallops(user, text);
500 return true;
501 },
502 irc_RPL_CREATIONTIME: function(prefix, params) {
503 var channel = params[1];
504 var time = params[2];
505
506 this.channelCreationTime(channel, time);
507 return true;
508 },
509 irc_RPL_CHANNELMODEIS: function(prefix, params) {
510 var channel = params[1];
511 var modes = params.slice(2);
512
513 this.channelModeIs(channel, modes);
514 return true;
515 },
516 irc_SILENCE: function(prefix, params) {
517 var host = params[0];
518 this.silenced(host);
519 return true;
520 },
521 irc_QWEBIRCIMAGE: function(prefix, params) {
522 var target = params[0];
523 var url = params.indexFromEnd(-1);
524 return this.qwebircImage(target, url);
525 }
526 });