]>
Commit | Line | Data |
---|---|---|
e20e5a6b CP |
1 | qwebirc.irc.IRCClient = new Class({ |
2 | Extends: qwebirc.irc.BaseIRCClient, | |
9e769c12 | 3 | options: { |
e20e5a6b | 4 | nickname: "qwebirc", |
12ac5868 CP |
5 | autojoin: "", |
6 | maxnicks: 10 | |
9e769c12 CP |
7 | }, |
8 | initialize: function(options, ui) { | |
9 | this.parent(options); | |
10 | ||
11 | this.ui = ui; | |
12 | ||
13 | this.prefixes = "@+"; | |
14 | this.modeprefixes = "ov"; | |
15 | this.windows = {}; | |
16 | ||
e20e5a6b | 17 | this.commandparser = new qwebirc.irc.CommandParser(this); |
9e769c12 CP |
18 | this.exec = this.commandparser.dispatch.bind(this.commandparser); |
19 | ||
20 | this.statusWindow = this.ui.newClient(this); | |
12ac5868 | 21 | this.lastNicks = []; |
9e769c12 CP |
22 | }, |
23 | newLine: function(window, type, data) { | |
24 | if(!data) | |
25 | data = {}; | |
26 | ||
27 | var w = this.getWindow(window); | |
28 | if(w) { | |
29 | w.addLine(type, data); | |
30 | } else { | |
31 | this.statusWindow.addLine(type, data); | |
32 | } | |
33 | }, | |
34 | newChanLine: function(channel, type, user, extra) { | |
35 | if(!extra) | |
36 | extra = {}; | |
37 | ||
38 | extra["n"] = user.hostToNick(); | |
39 | extra["h"] = user.hostToHost(); | |
40 | extra["c"] = channel; | |
41 | extra["-"] = this.nickname; | |
42 | ||
43 | this.newLine(channel, type, extra); | |
44 | }, | |
45 | newServerLine: function(type, data) { | |
46 | this.statusWindow.addLine(type, data); | |
47 | }, | |
48 | newActiveLine: function(type, data) { | |
1d42a76f | 49 | this.getActiveWindow().addLine(type, data); |
9e769c12 | 50 | }, |
1d6756bc CP |
51 | newTargetOrActiveLine: function(target, type, data) { |
52 | if(this.getWindow(target)) { | |
53 | this.newLine(target, type, data); | |
54 | } else { | |
55 | this.newActiveLine(type, data); | |
56 | } | |
57 | }, | |
9e769c12 CP |
58 | updateNickList: function(channel) { |
59 | var n1 = this.tracker.getChannel(channel); | |
60 | var names = new Array(); | |
61 | var tff = String.fromCharCode(255); | |
62 | var nh = {} | |
63 | ||
64 | /* MEGAHACK */ | |
65 | for(var n in n1) { | |
66 | var nc = n1[n]; | |
67 | var nx; | |
68 | ||
69 | if(nc.prefixes.length > 0) { | |
70 | var c = nc.prefixes.charAt(0); | |
71 | nx = String.fromCharCode(this.prefixes.indexOf(c)) + n.toIRCLower(); | |
72 | nh[nx] = c + n; | |
73 | } else { | |
74 | nx = tff + n.toIRCLower(); | |
75 | nh[nx] = n; | |
76 | } | |
77 | names.push(nx); | |
78 | }; | |
79 | ||
80 | names.sort(); | |
81 | ||
82 | var sortednames = new Array(); | |
83 | names.each(function(name) { | |
84 | sortednames.push(nh[name]); | |
85 | }); | |
86 | ||
87 | var w = this.getWindow(channel); | |
88 | if(w) | |
89 | w.updateNickList(sortednames); | |
90 | }, | |
91 | getWindow: function(name) { | |
92 | return this.windows[name]; | |
93 | }, | |
94 | newWindow: function(name, type, select) { | |
95 | var w = this.getWindow(name); | |
96 | if(!w) { | |
97 | w = this.windows[name] = this.ui.newWindow(this, type, name); | |
98 | ||
99 | w.addEvent("close", function(w) { | |
100 | delete this.windows[name]; | |
101 | }.bind(this)); | |
102 | } | |
103 | ||
104 | if(select) | |
105 | this.ui.selectWindow(w); | |
106 | ||
107 | return w; | |
108 | }, | |
f74802c5 CP |
109 | newQueryWindow: function(name) { |
110 | if(this.ui.uiOptions.DEDICATED_MSG_WINDOW) | |
111 | return this.ui.newWindow(this, qwebirc.ui.WINDOW_MESSAGES, "Messages"); | |
112 | return this.newWindow(name, qwebirc.ui.WINDOW_QUERY, false); | |
113 | }, | |
114 | newQueryLine: function(window, type, data, active) { | |
115 | if(this.getWindow(window)) | |
116 | return this.newLine(window, type, data); | |
117 | ||
118 | var w = this.ui.getWindow(this, qwebirc.ui.WINDOW_MESSAGES); | |
119 | ||
120 | if(this.ui.uiOptions.DEDICATED_MSG_WINDOW && w) { | |
121 | return w.addLine(type, data); | |
122 | } else { | |
123 | if(active) { | |
124 | return this.newActiveLine(window, type, data); | |
125 | } else { | |
126 | return this.newLine(window, type, data); | |
127 | } | |
128 | } | |
129 | }, | |
130 | newQueryOrActiveLine: function(window, type, data) { | |
131 | this.newQueryLine(window, type, data, true); | |
132 | }, | |
9e769c12 | 133 | getActiveWindow: function() { |
1d42a76f | 134 | return this.ui.getActiveIRCWindow(this); |
9e769c12 CP |
135 | }, |
136 | getNickname: function() { | |
137 | return this.nickname; | |
138 | }, | |
139 | addPrefix: function(nickchanentry, prefix) { | |
140 | var ncp = nickchanentry.prefixes + prefix; | |
141 | var prefixes = []; | |
142 | ||
143 | /* O(n^2) */ | |
144 | for(var i=0;i<this.prefixes.length;i++) { | |
145 | var pc = this.prefixes.charAt(i); | |
146 | var index = ncp.indexOf(pc); | |
147 | if(index != -1) | |
148 | prefixes.push(pc); | |
149 | } | |
150 | ||
151 | nickchanentry.prefixes = prefixes.join(""); | |
152 | }, | |
52090a1f CP |
153 | stripPrefix: function(nick) { |
154 | var l = nick.charAt(0); | |
155 | if(!l) | |
156 | return nick; | |
157 | ||
158 | if(this.prefixes.indexOf(l) != -1) | |
159 | return nick.substring(1); | |
160 | ||
161 | return nick; | |
162 | }, | |
9e769c12 CP |
163 | removePrefix: function(nickchanentry, prefix) { |
164 | nickchanentry.prefixes = nickchanentry.prefixes.replaceAll(prefix, ""); | |
165 | }, | |
166 | ||
167 | /* from here down are events */ | |
168 | rawNumeric: function(numeric, prefix, params) { | |
169 | this.newServerLine("RAW", {"n": "numeric", "m": params.slice(1).join(" ")}); | |
170 | }, | |
171 | signedOn: function(nickname) { | |
e20e5a6b | 172 | this.tracker = new qwebirc.irc.IRCTracker(); |
9e769c12 CP |
173 | this.nickname = nickname; |
174 | this.newServerLine("SIGNON"); | |
175 | ||
eb9b087b CP |
176 | if(this.options.autojoin) |
177 | this.send("JOIN " + this.options.autojoin); | |
9e769c12 CP |
178 | }, |
179 | userJoined: function(user, channel) { | |
180 | var nick = user.hostToNick(); | |
181 | var host = user.hostToHost(); | |
182 | ||
183 | if((nick == this.nickname) && !this.getWindow(channel)) | |
34222b40 | 184 | this.newWindow(channel, qwebirc.ui.WINDOW_CHANNEL, true); |
9e769c12 CP |
185 | this.tracker.addNickToChannel(nick, channel); |
186 | ||
ebb220d3 CP |
187 | if(nick == this.nickname) { |
188 | this.newChanLine(channel, "OURJOIN", user); | |
189 | } else { | |
190 | this.newChanLine(channel, "JOIN", user); | |
191 | } | |
9e769c12 CP |
192 | this.updateNickList(channel); |
193 | }, | |
194 | userPart: function(user, channel, message) { | |
195 | var nick = user.hostToNick(); | |
196 | var host = user.hostToHost(); | |
197 | ||
198 | if(nick == this.nickname) { | |
199 | this.tracker.removeChannel(channel); | |
200 | } else { | |
201 | this.tracker.removeNickFromChannel(nick, channel); | |
202 | this.newChanLine(channel, "PART", user, {"m": message}); | |
203 | } | |
204 | ||
205 | this.updateNickList(channel); | |
206 | ||
3d64f569 CP |
207 | if(nick == this.nickname) { |
208 | var w = this.getWindow(channel) | |
209 | if(w) | |
210 | w.close(); | |
211 | } | |
9e769c12 CP |
212 | }, |
213 | userKicked: function(kicker, channel, kickee, message) { | |
214 | if(kickee == this.nickname) { | |
215 | this.tracker.removeChannel(channel); | |
216 | this.getWindow(channel).close(); | |
217 | } else { | |
218 | this.tracker.removeNickFromChannel(kickee, channel); | |
219 | this.updateNickList(channel); | |
220 | } | |
221 | ||
222 | this.newChanLine(channel, "KICK", kicker, {"v": kickee, "m": message}); | |
223 | }, | |
224 | channelMode: function(user, channel, modes, raw) { | |
225 | modes.each(function(mo) { | |
226 | var direction = mo[0]; | |
227 | var mode = mo[1]; | |
228 | ||
229 | var prefixindex = this.modeprefixes.indexOf(mode); | |
230 | if(prefixindex == -1) | |
231 | return; | |
232 | ||
233 | var nick = mo[2]; | |
234 | var prefixchar = this.prefixes.charAt(prefixindex); | |
235 | ||
236 | var nc = this.tracker.getOrCreateNickOnChannel(nick, channel); | |
237 | if(direction == "-") { | |
238 | this.removePrefix(nc, prefixchar); | |
239 | } else { | |
240 | this.addPrefix(nc, prefixchar); | |
241 | } | |
242 | }, this); | |
243 | ||
244 | this.newChanLine(channel, "MODE", user, {"m": raw.join(" ")}); | |
245 | ||
246 | this.updateNickList(channel); | |
247 | }, | |
248 | userQuit: function(user, message) { | |
249 | var nick = user.hostToNick(); | |
250 | ||
251 | var channels = this.tracker.getNick(nick); | |
252 | ||
253 | var clist = []; | |
254 | for(var c in channels) { | |
255 | clist.push(c); | |
256 | this.newChanLine(c, "QUIT", user, {"m": message}); | |
257 | } | |
258 | ||
259 | this.tracker.removeNick(nick); | |
260 | ||
261 | clist.each(function(cli) { | |
262 | this.updateNickList(cli); | |
263 | }, this); | |
264 | }, | |
265 | nickChanged: function(user, newnick) { | |
266 | var oldnick = user.hostToNick(); | |
267 | ||
268 | if(oldnick == this.nickname) | |
269 | this.nickname = newnick; | |
270 | ||
271 | this.tracker.renameNick(oldnick, newnick); | |
272 | ||
273 | var channels = this.tracker.getNick(newnick); | |
10952f4b | 274 | var found = false; |
9e769c12 CP |
275 | |
276 | for(var c in channels) { | |
10952f4b CP |
277 | var found = true; |
278 | ||
9e769c12 CP |
279 | this.newChanLine(c, "NICK", user, {"w": newnick}); |
280 | /* TODO: rename queries */ | |
281 | this.updateNickList(c); | |
282 | } | |
33503312 | 283 | |
10952f4b CP |
284 | if(!found) |
285 | this.newChanLine(undefined, "NICK", user, {"w": newnick}); | |
9e769c12 CP |
286 | }, |
287 | channelTopic: function(user, channel, topic) { | |
288 | this.newChanLine(channel, "TOPIC", user, {"m": topic}); | |
289 | this.getWindow(channel).updateTopic(topic); | |
290 | }, | |
291 | initialTopic: function(channel, topic) { | |
292 | this.getWindow(channel).updateTopic(topic); | |
293 | }, | |
294 | channelCTCP: function(user, channel, type, args) { | |
295 | if(args == undefined) | |
296 | args = ""; | |
297 | ||
298 | if(type == "ACTION") { | |
e95f04c4 | 299 | this.tracker.updateLastSpoke(user.hostToNick(), channel, new Date().getTime()); |
be7754cd | 300 | this.newChanLine(channel, "CHANACTION", user, {"m": args, "c": channel, "@": this.getNickStatus(channel, nick)}); |
9e769c12 CP |
301 | return; |
302 | } | |
303 | ||
be7754cd | 304 | this.newChanLine(channel, "CHANCTCP", user, {"x": type, "m": args, "c": channel, "@": this.getNickStatus(channel, nick)}); |
9e769c12 CP |
305 | }, |
306 | userCTCP: function(user, type, args) { | |
307 | var nick = user.hostToNick(); | |
308 | var host = user.hostToHost(); | |
309 | if(args == undefined) | |
310 | args = ""; | |
311 | ||
312 | if(type == "ACTION") { | |
f74802c5 CP |
313 | this.newQueryWindow(nick); |
314 | this.newQueryLine(nick, "PRIVACTION", {"m": args, "x": type, "h": host, "n": nick}); | |
9e769c12 CP |
315 | return; |
316 | } | |
317 | ||
1d6756bc | 318 | this.newTargetOrActiveLine(nick, "PRIVCTCP", {"m": args, "x": type, "h": host, "n": nick, "-": this.nickname}); |
9e769c12 CP |
319 | }, |
320 | userCTCPReply: function(user, type, args) { | |
321 | var nick = user.hostToNick(); | |
322 | var host = user.hostToHost(); | |
323 | if(args == undefined) | |
324 | args = ""; | |
325 | ||
1d6756bc | 326 | this.newTargetOrActiveLine(nick, "CTCPREPLY", {"m": args, "x": type, "h": host, "n": nick, "-": this.nickname}); |
9e769c12 | 327 | }, |
c6b78d06 CP |
328 | getNickStatus: function(channel, nick) { |
329 | var n = this.tracker.getNickOnChannel(nick, channel); | |
330 | if(!$defined(n)) | |
331 | return ""; | |
332 | ||
333 | if(n.prefixes.length == 0) | |
334 | return ""; | |
335 | ||
336 | return n.prefixes.charAt(0); | |
337 | }, | |
9e769c12 | 338 | channelPrivmsg: function(user, channel, message) { |
c6b78d06 CP |
339 | var nick = user.hostToNick(); |
340 | ||
341 | this.tracker.updateLastSpoke(nick, channel, new Date().getTime()); | |
342 | this.newChanLine(channel, "CHANMSG", user, {"m": message, "@": this.getNickStatus(channel, nick)}); | |
9e769c12 CP |
343 | }, |
344 | channelNotice: function(user, channel, message) { | |
be7754cd | 345 | this.newChanLine(channel, "CHANNOTICE", user, {"m": message, "@": this.getNickStatus(channel, nick)}); |
9e769c12 CP |
346 | }, |
347 | userPrivmsg: function(user, message) { | |
348 | var nick = user.hostToNick(); | |
349 | var host = user.hostToHost(); | |
350 | ||
f74802c5 | 351 | this.newQueryWindow(nick); |
12ac5868 | 352 | this.pushLastNick(nick); |
f74802c5 | 353 | this.newQueryLine(nick, "PRIVMSG", {"m": message, "h": host, "n": nick}); |
9e769c12 CP |
354 | }, |
355 | serverNotice: function(message) { | |
356 | this.newServerLine("SERVERNOTICE", {"m": message}); | |
357 | }, | |
358 | userNotice: function(user, message) { | |
359 | var nick = user.hostToNick(); | |
360 | var host = user.hostToHost(); | |
361 | ||
1d6756bc | 362 | this.newTargetOrActiveLine(nick, "PRIVNOTICE", {"m": message, "h": host, "n": nick}); |
9e769c12 CP |
363 | }, |
364 | userInvite: function(user, channel) { | |
365 | var nick = user.hostToNick(); | |
366 | var host = user.hostToHost(); | |
367 | ||
368 | this.newServerLine("INVITE", {"c": channel, "h": host, "n": nick}); | |
369 | }, | |
370 | userMode: function(modes) { | |
371 | this.newServerLine("UMODE", {"m": modes, "n": this.nickname}); | |
372 | }, | |
373 | channelNames: function(channel, names) { | |
374 | if(names.length == 0) { | |
375 | this.updateNickList(channel); | |
376 | return; | |
377 | } | |
378 | ||
379 | names.each(function(nick) { | |
380 | var prefixes = []; | |
381 | var splitnick = nick.split(""); | |
382 | ||
383 | splitnick.every(function(c, i) { | |
384 | if(this.prefixes.indexOf(c) == -1) { | |
385 | nick = nick.substr(i); | |
386 | return false; | |
387 | } | |
388 | ||
389 | prefixes.push(c); | |
390 | return true; | |
391 | }, this); | |
392 | ||
393 | var nc = this.tracker.addNickToChannel(nick, channel); | |
394 | prefixes.each(function(p) { | |
395 | this.addPrefix(nc, p); | |
396 | }, this); | |
397 | }, this); | |
398 | }, | |
8dc46dfa | 399 | disconnected: function(message) { |
65152b01 CP |
400 | for(var x in this.windows) { |
401 | var w = this.windows[x]; | |
34222b40 | 402 | if(w.type == qwebirc.ui.WINDOW_CHANNEL) |
65152b01 CP |
403 | w.close(); |
404 | } | |
9e769c12 CP |
405 | this.tracker = undefined; |
406 | ||
8dc46dfa | 407 | this.newServerLine("DISCONNECT", {"m": message}); |
9e769c12 CP |
408 | }, |
409 | supported: function(key, value) { | |
410 | if(key == "PREFIX") { | |
411 | var l = (value.length - 2) / 2; | |
412 | ||
413 | this.modeprefixes = value.substr(1, l); | |
414 | this.prefixes = value.substr(l + 2, l); | |
415 | } | |
416 | }, | |
417 | connected: function() { | |
418 | this.newServerLine("CONNECT"); | |
419 | }, | |
420 | serverError: function(message) { | |
421 | this.newServerLine("ERROR", {"m": message}); | |
d65fe45f CP |
422 | }, |
423 | quit: function(message) { | |
424 | this.send("QUIT :" + message); | |
425 | this.disconnect(); | |
1d6756bc CP |
426 | }, |
427 | awayMessage: function(nick, message) { | |
f74802c5 | 428 | this.newQueryLine(nick, "AWAY", {"n": nick, "m": message}); |
1d6756bc CP |
429 | }, |
430 | whois: function(nick, type, data) { | |
431 | var ndata = {"n": nick}; | |
432 | var mtype; | |
433 | ||
434 | var xsend = function() { | |
435 | this.newTargetOrActiveLine(nick, "WHOIS" + mtype, ndata); | |
436 | }.bind(this); | |
437 | ||
438 | if(type == "user") { | |
439 | mtype = "USER"; | |
440 | ndata.h = data.ident + "@" + data.hostname; | |
441 | xsend(); | |
442 | mtype = "REALNAME"; | |
443 | ndata.m = data.realname; | |
444 | } else if(type == "server") { | |
445 | mtype = "SERVER"; | |
446 | ndata.x = data.server; | |
447 | ndata.m = data.serverdesc; | |
448 | } else if(type == "oper") { | |
449 | mtype = "OPER"; | |
450 | } else if(type == "idle") { | |
451 | mtype = "IDLE"; | |
452 | ndata.x = qwebirc.util.longtoduration(data.idle); | |
453 | ndata.m = qwebirc.irc.IRCDate(new Date(data.connected * 1000)); | |
454 | } else if(type == "channels") { | |
455 | mtype = "CHANNELS"; | |
456 | ndata.m = data.channels; | |
457 | } else if(type == "account") { | |
458 | mtype = "ACCOUNT"; | |
459 | ndata.m = data.account; | |
460 | } else if(type == "away") { | |
461 | mtype = "AWAY"; | |
462 | ndata.m = data.away; | |
463 | } else if(type == "opername") { | |
464 | mtype = "OPERNAME"; | |
465 | ndata.m = data.opername; | |
466 | } else if(type == "actually") { | |
467 | mtype = "ACTUALLY"; | |
468 | ndata.m = data.hostname; | |
469 | ndata.x = data.ip; | |
470 | } else if(type == "end") { | |
471 | mtype = "END"; | |
472 | } else { | |
473 | return false; | |
474 | } | |
475 | ||
476 | xsend(); | |
477 | return true; | |
14260d5f | 478 | }, |
96f28062 | 479 | genericError: function(target, message) { |
14260d5f | 480 | this.newTargetOrActiveLine(target, "GENERICERROR", {m: message, t: target}); |
574dff59 | 481 | }, |
f74802c5 CP |
482 | genericQueryError: function(target, message) { |
483 | this.newQueryOrActiveLine(target, "GENERICERROR", {m: message, t: target}); | |
484 | }, | |
574dff59 CP |
485 | awayStatus: function(state, message) { |
486 | this.newActiveLine("GENERICMESSAGE", {m: message}); | |
12ac5868 CP |
487 | }, |
488 | pushLastNick: function(nick) { | |
489 | var i = this.lastNicks.indexOf(nick); | |
490 | if(i != -1) { | |
491 | this.lastNicks.splice(i, 1); | |
492 | } else { | |
493 | if(this.lastNicks.length == this.options.maxnicks) | |
494 | this.lastNicks.pop(); | |
495 | } | |
496 | this.lastNicks.unshift(nick); | |
9e769c12 CP |
497 | } |
498 | }); |