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