]>
jfr.im git - irc/quakenet/qwebirc.git/blob - js/irc/ircclient.js
75bd25976f7cc2d3132911a585f275bbccb04172
1 qwebirc
.irc
.IRCClient
= new Class({
2 Extends: qwebirc
.irc
.BaseIRCClient
,
8 initialize: function(options
, ui
) {
14 this.modeprefixes
= "ov";
17 this.commandparser
= new qwebirc
.irc
.Commands(this);
18 this.exec
= this.commandparser
.dispatch
.bind(this.commandparser
);
20 this.statusWindow
= this.ui
.newClient(this);
23 this.inviteChanList
= [];
24 this.activeTimers
= {};
26 this.loginRegex
= new RegExp(this.ui
.options
.loginRegex
);
27 this.tracker
= new qwebirc
.irc
.IRCTracker(this);
29 newLine: function(window
, type
, data
) {
33 var w
= this.getWindow(window
);
35 w
.addLine(type
, data
);
37 this.statusWindow
.addLine(type
, data
);
40 newChanLine: function(channel
, type
, user
, extra
) {
45 extra
["n"] = user
.hostToNick();
46 extra
["h"] = user
.hostToHost();
49 extra
["-"] = this.nickname
;
51 if(!(this.ui
.uiOptions
.NICK_OV_STATUS
))
54 this.newLine(channel
, type
, extra
);
56 newServerLine: function(type
, data
) {
57 this.statusWindow
.addLine(type
, data
);
59 newActiveLine: function(type
, data
) {
60 this.getActiveWindow().addLine(type
, data
);
62 newTargetOrActiveLine: function(target
, type
, data
) {
63 if(this.getWindow(target
)) {
64 this.newLine(target
, type
, data
);
66 this.newActiveLine(type
, data
);
69 updateNickList: function(channel
) {
70 var n1
= this.tracker
.getChannel(channel
);
71 var names
= new Array();
72 var tff
= String
.fromCharCode(255);
80 if(nc
.prefixes
.length
> 0) {
81 var c
= nc
.prefixes
.charAt(0);
82 nx
= String
.fromCharCode(this.prefixes
.indexOf(c
)) + this.toIRCLower(n
);
85 nx
= tff
+ this.toIRCLower(n
);
93 var sortednames
= new Array();
94 names
.each(function(name
) {
95 sortednames
.push(nh
[name
]);
98 var w
= this.getWindow(channel
);
100 w
.updateNickList(sortednames
);
102 getWindow: function(name
) {
103 return this.windows
[this.toIRCLower(name
)];
105 renameWindow: function(oldname
, newname
) {
106 var oldwindow
= this.getWindow(oldname
);
107 if(!oldwindow
|| this.getWindow(newname
))
110 var window
= this.ui
.renameWindow(oldwindow
, newname
);
112 this.windows
[this.toIRCLower(newname
)] = window
;
113 delete this.windows
[this.toIRCLower(oldname
)];
116 newWindow: function(name
, type
, select
) {
117 var w
= this.getWindow(name
);
119 w
= this.windows
[this.toIRCLower(name
)] = this.ui
.newWindow(this, type
, name
);
121 w
.addEvent("close", function(w
) {
122 delete this.windows
[this.toIRCLower(name
)];
127 this.ui
.selectWindow(w
);
131 getQueryWindow: function(name
) {
132 return this.ui
.getWindow(this, qwebirc
.ui
.WINDOW_QUERY
, name
);
134 newQueryWindow: function(name
, privmsg
) {
137 if(this.getQueryWindow(name
))
141 return this.newPrivmsgQueryWindow(name
);
142 return this.newNoticeQueryWindow(name
);
144 newPrivmsgQueryWindow: function(name
) {
145 if(this.ui
.uiOptions
.DEDICATED_MSG_WINDOW
) {
146 if(!this.ui
.getWindow(this, qwebirc
.ui
.WINDOW_MESSAGES
))
147 return this.ui
.newWindow(this, qwebirc
.ui
.WINDOW_MESSAGES
, "Messages");
149 return this.newWindow(name
, qwebirc
.ui
.WINDOW_QUERY
, false);
152 newNoticeQueryWindow: function(name
) {
153 if(this.ui
.uiOptions
.DEDICATED_NOTICE_WINDOW
)
154 if(!this.ui
.getWindow(this, qwebirc
.ui
.WINDOW_MESSAGES
))
155 return this.ui
.newWindow(this, qwebirc
.ui
.WINDOW_MESSAGES
, "Messages");
157 newQueryLine: function(window
, type
, data
, privmsg
, active
) {
158 if(this.getQueryWindow(window
))
159 return this.newLine(window
, type
, data
);
161 var w
= this.ui
.getWindow(this, qwebirc
.ui
.WINDOW_MESSAGES
);
165 e
= this.ui
.uiOptions
.DEDICATED_MSG_WINDOW
;
167 e
= this.ui
.uiOptions
.DEDICATED_NOTICE_WINDOW
;
170 return w
.addLine(type
, data
);
173 return this.newActiveLine(type
, data
);
175 return this.newLine(window
, type
, data
);
179 newQueryOrActiveLine: function(window
, type
, data
, privmsg
) {
180 this.newQueryLine(window
, type
, data
, privmsg
, true);
182 getActiveWindow: function() {
183 return this.ui
.getActiveIRCWindow(this);
185 getNickname: function() {
186 return this.nickname
;
188 addPrefix: function(nickchanentry
, prefix
) {
189 var ncp
= nickchanentry
.prefixes
+ prefix
;
193 for(var i
=0;i
<this.prefixes
.length
;i
++) {
194 var pc
= this.prefixes
.charAt(i
);
195 var index
= ncp
.indexOf(pc
);
200 nickchanentry
.prefixes
= prefixes
.join("");
202 stripPrefix: function(nick
) {
203 var l
= nick
.charAt(0);
207 if(this.prefixes
.indexOf(l
) != -1)
208 return nick
.substring(1);
212 removePrefix: function(nickchanentry
, prefix
) {
213 nickchanentry
.prefixes
= nickchanentry
.prefixes
.replaceAll(prefix
, "");
216 /* from here down are events */
217 rawNumeric: function(numeric
, prefix
, params
) {
218 this.newServerLine("RAW", {"n": "numeric", "m": params
.slice(1).join(" ")});
220 signedOn: function(nickname
) {
221 this.tracker
= new qwebirc
.irc
.IRCTracker(this);
222 this.nickname
= nickname
;
223 this.newServerLine("SIGNON");
225 /* we guarantee that +x is sent out before the joins */
226 if(this.ui
.uiOptions
.USE_HIDDENHOST
)
227 this.exec("/UMODE +x");
229 if(this.options
.autojoin
) {
230 if(qwebirc
.auth
.loggedin() && this.ui
.uiOptions
.USE_HIDDENHOST
) {
232 if($defined(this.activeTimers
.autojoin
))
233 this.ui
.getActiveWindow().infoMessage("Waiting for login before joining channels...");
235 this.activeTimers
.autojoin = function() {
236 var w
= this.ui
.getActiveWindow();
237 w
.errorMessage("No login response in 10 seconds.");
238 w
.errorMessage("You may want to try authing manually and then type: /autojoin (if you don't auth your host may be visible).");
239 }.delay(10000, this);
243 this.exec("/AUTOJOIN");
246 userJoined: function(user
, channel
) {
247 var nick
= user
.hostToNick();
248 var host
= user
.hostToHost();
250 if((nick
== this.nickname
) && !this.getWindow(channel
))
251 this.newWindow(channel
, qwebirc
.ui
.WINDOW_CHANNEL
, true);
252 this.tracker
.addNickToChannel(nick
, channel
);
254 if(nick
== this.nickname
) {
255 this.newChanLine(channel
, "OURJOIN", user
);
257 if(!this.ui
.uiOptions
.HIDE_JOINPARTS
) {
258 this.newChanLine(channel
, "JOIN", user
);
261 this.updateNickList(channel
);
263 userPart: function(user
, channel
, message
) {
264 var nick
= user
.hostToNick();
265 var host
= user
.hostToHost();
267 if(nick
== this.nickname
) {
268 this.tracker
.removeChannel(channel
);
270 this.tracker
.removeNickFromChannel(nick
, channel
);
271 if(!this.ui
.uiOptions
.HIDE_JOINPARTS
) {
272 this.newChanLine(channel
, "PART", user
, {"m": message
});
276 this.updateNickList(channel
);
278 if(nick
== this.nickname
) {
279 var w
= this.getWindow(channel
)
284 userKicked: function(kicker
, channel
, kickee
, message
) {
285 if(kickee
== this.nickname
) {
286 this.tracker
.removeChannel(channel
);
287 this.getWindow(channel
).close();
289 this.tracker
.removeNickFromChannel(kickee
, channel
);
290 this.updateNickList(channel
);
293 this.newChanLine(channel
, "KICK", kicker
, {"v": kickee
, "m": message
});
295 channelMode: function(user
, channel
, modes
, raw
) {
296 modes
.each(function(mo
) {
297 var direction
= mo
[0];
300 var prefixindex
= this.modeprefixes
.indexOf(mode
);
301 if(prefixindex
== -1)
305 var prefixchar
= this.prefixes
.charAt(prefixindex
);
307 var nc
= this.tracker
.getOrCreateNickOnChannel(nick
, channel
);
308 if(direction
== "-") {
309 this.removePrefix(nc
, prefixchar
);
311 this.addPrefix(nc
, prefixchar
);
315 this.newChanLine(channel
, "MODE", user
, {"m": raw
.join(" ")});
317 this.updateNickList(channel
);
319 userQuit: function(user
, message
) {
320 var nick
= user
.hostToNick();
322 var channels
= this.tracker
.getNick(nick
);
325 for(var c
in channels
) {
327 if(!this.ui
.uiOptions
.HIDE_JOINPARTS
) {
328 this.newChanLine(c
, "QUIT", user
, {"m": message
});
332 this.tracker
.removeNick(nick
);
334 clist
.each(function(cli
) {
335 this.updateNickList(cli
);
338 nickChanged: function(user
, newnick
) {
339 var oldnick
= user
.hostToNick();
341 if(oldnick
== this.nickname
)
342 this.nickname
= newnick
;
344 this.tracker
.renameNick(oldnick
, newnick
);
346 var channels
= this.tracker
.getNick(newnick
);
349 for(var c
in channels
) {
352 this.newChanLine(c
, "NICK", user
, {"w": newnick
});
353 this.updateNickList(c
);
356 if(this.getQueryWindow(oldnick
)) {
358 this.renameWindow(oldnick
, newnick
);
359 this.newLine(newnick
, "NICK", {"n": oldnick
, "w": newnick
});
362 /* this is quite horrible */
364 this.newServerLine("NICK", {"w": newnick
, n: user
.hostToNick(), h: user
.hostToHost(), "-": this.nickname
});
366 channelTopic: function(user
, channel
, topic
) {
367 this.newChanLine(channel
, "TOPIC", user
, {"m": topic
});
368 this.getWindow(channel
).updateTopic(topic
);
370 initialTopic: function(channel
, topic
) {
371 this.getWindow(channel
).updateTopic(topic
);
373 channelCTCP: function(user
, channel
, type
, args
) {
374 if(args
== undefined)
377 var nick
= user
.hostToNick();
378 if(type
== "ACTION") {
379 this.tracker
.updateLastSpoke(nick
, channel
, new Date().getTime());
380 this.newChanLine(channel
, "CHANACTION", user
, {"m": args
, "c": channel
, "@": this.getNickStatus(channel
, nick
)});
384 this.newChanLine(channel
, "CHANCTCP", user
, {"x": type
, "m": args
, "c": channel
, "@": this.getNickStatus(channel
, nick
)});
386 userCTCP: function(user
, type
, args
) {
387 var nick
= user
.hostToNick();
388 var host
= user
.hostToHost();
389 if(args
== undefined)
392 if(type
== "ACTION") {
393 this.newQueryWindow(nick
, true);
394 this.newQueryLine(nick
, "PRIVACTION", {"m": args
, "x": type
, "h": host
, "n": nick
}, true);
398 this.newTargetOrActiveLine(nick
, "PRIVCTCP", {"m": args
, "x": type
, "h": host
, "n": nick
, "-": this.nickname
});
400 userCTCPReply: function(user
, type
, args
) {
401 var nick
= user
.hostToNick();
402 var host
= user
.hostToHost();
403 if(args
== undefined)
406 this.newTargetOrActiveLine(nick
, "CTCPREPLY", {"m": args
, "x": type
, "h": host
, "n": nick
, "-": this.nickname
});
408 getNickStatus: function(channel
, nick
) {
409 var n
= this.tracker
.getNickOnChannel(nick
, channel
);
413 if(n
.prefixes
.length
== 0)
416 return n
.prefixes
.charAt(0);
418 channelPrivmsg: function(user
, channel
, message
) {
419 var nick
= user
.hostToNick();
421 this.tracker
.updateLastSpoke(nick
, channel
, new Date().getTime());
422 this.newChanLine(channel
, "CHANMSG", user
, {"m": message
, "@": this.getNickStatus(channel
, nick
)});
424 channelNotice: function(user
, channel
, message
) {
425 this.newChanLine(channel
, "CHANNOTICE", user
, {"m": message
, "@": this.getNickStatus(channel
, user
.hostToNick())});
427 userPrivmsg: function(user
, message
) {
428 var nick
= user
.hostToNick();
429 var host
= user
.hostToHost();
430 this.newQueryWindow(nick
, true);
431 this.pushLastNick(nick
);
432 this.newQueryLine(nick
, "PRIVMSG", {"m": message
, "h": host
, "n": nick
}, true);
434 this.checkLogin(user
, message
);
436 checkLogin: function(user
, message
) {
437 if(this.isNetworkService(user
) && $defined(this.activeTimers
.autojoin
)) {
438 if($defined(this.loginRegex
) && message
.match(this.loginRegex
)) {
439 $clear(this.activeTimers
.autojoin
);
440 delete this.activeTimers
["autojoin"];
441 this.ui
.getActiveWindow().infoMessage("Joining channels...");
442 this.exec("/AUTOJOIN");
446 serverNotice: function(user
, message
) {
448 this.newServerLine("SERVERNOTICE", {"m": message
});
450 this.newServerLine("PRIVNOTICE", {"m": message
, "n": user
});
453 userNotice: function(user
, message
) {
454 var nick
= user
.hostToNick();
455 var host
= user
.hostToHost();
457 if(this.ui
.uiOptions
.DEDICATED_NOTICE_WINDOW
) {
458 this.newQueryWindow(nick
, false);
459 this.newQueryOrActiveLine(nick
, "PRIVNOTICE", {"m": message
, "h": host
, "n": nick
}, false);
461 this.newTargetOrActiveLine(nick
, "PRIVNOTICE", {"m": message
, "h": host
, "n": nick
});
464 this.checkLogin(user
, message
);
466 isNetworkService: function(user
) {
467 return this.ui
.options
.networkServices
.indexOf(user
) > -1;
469 __joinInvited: function() {
470 this.exec("/JOIN " + this.inviteChanList
.join(","));
471 this.inviteChanList
= [];
472 delete this.activeTimers
["serviceInvite"];
474 userInvite: function(user
, channel
) {
475 var nick
= user
.hostToNick();
476 var host
= user
.hostToHost();
478 this.newServerLine("INVITE", {"c": channel
, "h": host
, "n": nick
});
479 if(this.ui
.uiOptions
.ACCEPT_SERVICE_INVITES
&& this.isNetworkService(user
)) {
480 if(this.activeTimers
.serviceInvite
)
481 $clear(this.activeTimers
.serviceInvite
);
483 /* we do this so we can batch the joins, i.e. instead of sending 5 JOIN comands we send 1 with 5 channels. */
484 this.activeTimers
.serviceInvite
= this.__joinInvited
.delay(100, this);
486 this.inviteChanList
.push(channel
);
489 userMode: function(modes
) {
490 this.newServerLine("UMODE", {"m": modes
, "n": this.nickname
});
492 channelNames: function(channel
, names
) {
493 if(names
.length
== 0) {
494 this.updateNickList(channel
);
498 names
.each(function(nick
) {
500 var splitnick
= nick
.split("");
502 splitnick
.every(function(c
, i
) {
503 if(this.prefixes
.indexOf(c
) == -1) {
504 nick
= nick
.substr(i
);
512 var nc
= this.tracker
.addNickToChannel(nick
, channel
);
513 prefixes
.each(function(p
) {
514 this.addPrefix(nc
, p
);
518 disconnected: function(message
) {
519 for(var x
in this.windows
) {
520 var w
= this.windows
[x
];
521 if(w
.type
== qwebirc
.ui
.WINDOW_CHANNEL
)
524 this.tracker
= undefined;
526 this.newServerLine("DISCONNECT", {"m": message
});
528 nickOnChanHasPrefix: function(nick
, channel
, prefix
) {
529 var entry
= this.tracker
.getNickOnChannel(nick
, channel
);
531 return false; /* shouldn't happen */
533 return entry
.prefixes
.indexOf(prefix
) != -1;
535 nickOnChanHasAtLeastPrefix: function(nick
, channel
, prefix
) {
536 var entry
= this.tracker
.getNickOnChannel(nick
, channel
);
538 return false; /* shouldn't happen */
540 /* this array is sorted */
541 var pos
= this.prefixes
.indexOf(prefix
);
543 return false; /* shouldn't happen */
546 this.prefixes
.slice(0, pos
+ 1).split("").each(function(x
) {
550 var prefixes
= entry
.prefixes
;
551 for(var i
=0;i
<prefixes
.length
;i
++)
552 if(modehash
[prefixes
.charAt(i
)])
557 supported: function(key
, value
) {
558 if(key
== "PREFIX") {
559 var l
= (value
.length
- 2) / 2;
561 this.modeprefixes
= value
.substr(1, l
);
562 this.prefixes
= value
.substr(l
+ 2, l
);
565 this.parent(key
, value
);
567 connected: function() {
568 this.newServerLine("CONNECT");
570 serverError: function(message
) {
571 this.newServerLine("ERROR", {"m": message
});
573 quit: function(message
) {
574 this.send("QUIT :" + message
, true);
577 disconnect: function() {
578 for(var k
in this.activeTimers
) {
579 this.activeTimers
[k
].cancel();
581 this.activeTimers
= {};
585 awayMessage: function(nick
, message
) {
586 this.newQueryLine(nick
, "AWAY", {"n": nick
, "m": message
}, true);
588 whois: function(nick
, type
, data
) {
589 var ndata
= {"n": nick
};
592 var xsend = function() {
593 this.newTargetOrActiveLine(nick
, "WHOIS" + mtype
, ndata
);
598 ndata
.h
= data
.ident
+ "@" + data
.hostname
;
601 ndata
.m
= data
.realname
;
602 } else if(type
== "server") {
604 ndata
.x
= data
.server
;
605 ndata
.m
= data
.serverdesc
;
606 } else if(type
== "oper") {
608 } else if(type
== "idle") {
610 ndata
.x
= qwebirc
.util
.longtoduration(data
.idle
);
611 ndata
.m
= qwebirc
.irc
.IRCDate(new Date(data
.connected
* 1000));
612 } else if(type
== "channels") {
614 ndata
.m
= data
.channels
;
615 } else if(type
== "account") {
617 ndata
.m
= data
.account
;
618 } else if(type
== "away") {
621 } else if(type
== "opername") {
623 ndata
.m
= data
.opername
;
624 } else if(type
== "actually") {
626 ndata
.m
= data
.hostname
;
628 } else if(type
== "generictext") {
629 mtype
= "GENERICTEXT";
631 } else if(type
== "end") {
640 genericError: function(target
, message
) {
641 this.newTargetOrActiveLine(target
, "GENERICERROR", {m: message
, t: target
});
643 genericQueryError: function(target
, message
) {
644 this.newQueryOrActiveLine(target
, "GENERICERROR", {m: message
, t: target
}, true);
646 awayStatus: function(state
, message
) {
647 this.newActiveLine("GENERICMESSAGE", {m: message
});
649 pushLastNick: function(nick
) {
650 var i
= this.lastNicks
.indexOf(nick
);
652 this.lastNicks
.splice(i
, 1);
654 if(this.lastNicks
.length
== this.options
.maxnicks
)
655 this.lastNicks
.pop();
657 this.lastNicks
.unshift(nick
);
659 wallops: function(user
, text
) {
660 var nick
= user
.hostToNick();
661 var host
= user
.hostToHost();
663 this.newServerLine("WALLOPS", {t: text
, n: nick
, h: host
});
665 channelModeIs: function(channel
, modes
) {
666 this.newTargetOrActiveLine(channel
, "CHANNELMODEIS", {c: channel
, m: modes
.join(" ")});
668 channelCreationTime: function(channel
, time
) {
669 this.newTargetOrActiveLine(channel
, "CHANNELCREATIONTIME", {c: channel
, m: qwebirc
.irc
.IRCDate(new Date(time
* 1000))});