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