]> jfr.im git - irc/quakenet/qwebirc.git/blob - static/js/irc/ircclient.js
Add command parsing and lots of other stuff...
[irc/quakenet/qwebirc.git] / static / js / irc / ircclient.js
1 function IRCClient(nickname, ui) {
2 var self = this;
3 this.prefixes = "@+";
4 this.modeprefixes = "ov";
5
6 var newLine = function(window, type, data) {
7 if(!data)
8 data = {};
9
10 ui.newLine(window, type, data);
11 }
12
13 var newChanLine = function(channel, type, user, extra) {
14 if(!extra)
15 extra = {};
16
17 extra["n"] = hosttonick(user);
18 extra["h"] = hosttohost(user);
19 extra["c"] = channel;
20 extra["-"] = self.nickname;
21
22 newLine(channel, type, extra);
23 }
24
25 var newServerLine = function(type, data) {
26 newLine("", type, data);
27 }
28
29 var newActiveLine = function(type, data) {
30 newLine(false, type, data);
31 }
32
33 this.rawNumeric = function(numeric, prefix, params) {
34 newServerLine("RAW", {"n": "numeric", "m": params.slice(1).join(" ")});
35 }
36
37 this.signedOn = function(nickname) {
38 self.tracker = new IRCTracker();
39 self.nickname = nickname;
40 newServerLine("SIGNON");
41 }
42
43 this.updateNickList = function(channel) {
44 var n1 = self.tracker.getChannel(channel);
45 var names = new Array();
46 var tff = String.fromCharCode(255);
47 var nh = {}
48
49 /* MEGAHACK */
50 for(var n in n1) {
51 var nc = n1[n];
52 var nx;
53
54 if(nc.prefixes.length > 0) {
55 var c = nc.prefixes.charAt(0);
56 nx = String.fromCharCode(self.prefixes.indexOf(c)) + toIRCLower(n);
57 nh[nx] = c + n;
58 } else {
59 nx = tff + toIRCLower(n);
60 nh[nx] = n;
61 }
62 names.push(nx);
63 };
64
65 names.sort();
66
67 var sortednames = new Array();
68 forEach(names, function(name) {
69 sortednames.push(nh[name]);
70 });
71 ui.updateNickList(channel, sortednames);
72 }
73
74 this.userJoined = function(user, channel) {
75 var nick = hosttonick(user);
76 var host = hosttohost(user);
77
78 if(nick == self.nickname) {
79 ui.newWindow(channel, true);
80 ui.selectTab(channel);
81 }
82 self.tracker.addNickToChannel(nick, channel);
83
84 newChanLine(channel, "JOIN", user);
85
86 self.updateNickList(channel);
87 }
88
89 this.userPart = function(user, channel, message) {
90 var nick = hosttonick(user);
91 var host = hosttohost(user);
92
93 if(nick == self.nickname) {
94 self.tracker.removeChannel(channel);
95 } else {
96 self.tracker.removeNickFromChannel(nick, channel);
97 newChanLine(channel, "PART", user, {"m": message});
98 }
99
100 self.updateNickList(channel);
101
102 if(nick == self.nickname)
103 ui.closeWindow(channel);
104 }
105
106 this.userKicked = function(kicker, channel, kickee, message) {
107 if(kickee == self.nickname) {
108 self.tracker.removeChannel(channel);
109 ui.closeWindow(channel);
110 } else {
111 self.tracker.removeNickFromChannel(kickee, channel);
112 self.updateNickList(channel);
113 }
114
115 newChanLine(channel, "KICK", kicker, {"v": kickee, "m": message});
116 }
117
118 this.channelMode = function(user, channel, modes, raw) {
119 forEach(modes, function(mo) {
120 var direction = mo[0];
121 var mode = mo[1];
122
123 var prefixindex = self.modeprefixes.indexOf(mode);
124 if(prefixindex == -1)
125 return;
126
127 var nick = mo[2];
128 var prefixchar = self.prefixes.charAt(prefixindex);
129
130 var nc = self.tracker.getOrCreateNickOnChannel(nick, channel);
131 if(direction == "-") {
132 self.removePrefix(nc, prefixchar);
133 } else {
134 self.addPrefix(nc, prefixchar);
135 }
136 });
137
138 newChanLine(channel, "MODE", user, {"m": raw.join(" ")});
139
140 self.updateNickList(channel);
141 }
142
143 this.userQuit = function(user, message) {
144 var nick = hosttonick(user);
145
146 var channels = self.tracker.getNick(nick);
147
148 var clist = [];
149 for(var c in channels) {
150 clist.push(c);
151 newChanLine(c, "QUIT", user, {"m": message});
152 }
153
154 self.tracker.removeNick(nick);
155
156 forEach(clist, function(cli) {
157 self.updateNickList(cli);
158 });
159 }
160
161 this.nickChanged = function(user, newnick) {
162 var oldnick = hosttonick(user);
163
164 if(oldnick == self.nickname)
165 self.nickname = newnick;
166
167 self.tracker.renameNick(oldnick, newnick);
168
169 var channels = self.tracker.getNick(newnick);
170
171 for(var c in channels) {
172 newChanLine(c, "NICK", user, {"w": newnick});
173 /* TODO: rename queries */
174 self.updateNickList(c);
175 }
176 }
177
178 this.channelTopic = function(user, channel, topic) {
179 newChanLine(channel, "TOPIC", user, {"m": topic});
180 ui.updateTopic(channel, topic);
181 }
182
183 this.initialTopic = function(channel, topic) {
184 ui.updateTopic(channel, topic);
185 }
186
187 this.chanCTCP = function(user, channel, type, args) {
188 if(args == undefined)
189 args = "";
190
191 if(type == "ACTION") {
192 newChanLine(channel, "CHANACTION", user, {"m": args, "c": channel});
193 return;
194 }
195
196 newChanLine(channel, "CHANCTCP", user, {"x": type, "m": args, "c": channel});
197 }
198
199 this.userCTCP = function(user, type, args) {
200 var nick = hosttonick(user);
201 var host = hosttohost(user);
202 if(args == undefined)
203 args = "";
204
205 if(type == "ACTION") {
206 ui.newWindow(nick, false);
207 newLine(nick, "PRIVACTION", {"m": args, "x": type, "h": host, "n": nick});
208 return;
209 }
210
211 if(ui.getWindow(nick)) {
212 newLine(nick, "PRIVCTCP", {"m": args, "x": type, "h": host, "n": nick, "-": self.nickname});
213 } else {
214 newActiveLine("PRIVCTCP", {"m": args, "x": type, "h": host, "n": nick, "-": self.nickname});
215 }
216 }
217
218 this.userCTCPReply = function(user, type, args) {
219 var nick = hosttonick(user);
220 var host = hosttohost(user);
221 if(args == undefined)
222 args = "";
223
224 if(ui.getWindow(nick)) {
225 newLine(nick, "CTCPREPLY", {"m": args, "x": type, "h": host, "n": nick, "-": self.nickname});
226 } else {
227 newActiveLine("CTCPREPLY", {"m": args, "x": type, "h": host, "n": nick, "-": self.nickname});
228 }
229 }
230
231 this.channelPrivmsg = function(user, channel, message) {
232 newChanLine(channel, "CHANMSG", user, {"m": message});
233 }
234
235 this.channelNotice = function(user, channel, message) {
236 newChanLine(channel, "CHANNOTICE", user, {"m": message});
237 }
238
239 this.userPrivmsg = function(user, message) {
240 var nick = hosttonick(user);
241 var host = hosttohost(user);
242 ui.newWindow(nick, false);
243 newLine(nick, "PRIVMSG", {"m": message, "h": host, "n": nick});
244 }
245
246 this.serverNotice = function(message) {
247 newServerLine("SERVERNOTICE", {"m": message});
248 }
249
250 this.userNotice = function(user, message) {
251 var nick = hosttonick(user);
252 var host = hosttohost(user);
253
254 if(ui.getWindow(nick)) {
255 newLine(nick, "PRIVNOTICE", {"m": message, "h": host, "n": nick});
256 } else {
257 newActiveLine("PRIVNOTICE", {"m": message, "h": host, "n": nick});
258 }
259 }
260
261 this.userInvite = function(user, channel) {
262 var nick = hosttonick(user);
263 var host = hosttohost(user);
264
265 newServerLine("INVITE", {"c": channel, "h": host, "n": nick});
266 }
267
268 this.userMode = function(modes) {
269 newServerLine("UMODE", {"m": modes, "n": self.nickname});
270 }
271
272 this.addPrefix = function(nickchanentry, prefix) {
273 var ncp = nickchanentry.prefixes + prefix;
274 var prefixes = new Array();
275
276 /* O(n^2) */
277 for(var i=0;i<self.prefixes.length;i++) {
278 var pc = self.prefixes.charAt(i);
279 var index = ncp.indexOf(pc);
280 if(index != -1)
281 prefixes.push(pc);
282 }
283
284 nickchanentry.prefixes = prefixes.join("");
285 }
286
287 this.removePrefix = function(nickchanentry, prefix) {
288 nickchanentry.prefixes = nickchanentry.prefixes.replaceAll(prefix, "");
289 }
290
291 this.channelNames = function(channel, names) {
292 if(names.length == 0) {
293 self.updateNickList(channel);
294 return;
295 }
296
297 forEach(names, function(nick) {
298 var prefixes = [];
299 var splitnick = nick.split("");
300
301 var i = 0;
302 forEach(splitnick, function(c) {
303 if(self.prefixes.indexOf(c) == -1) {
304 nick = nick.substr(i);
305 return true;
306 }
307
308 prefixes.push(c);
309 i++;
310 });
311
312 var nc = self.tracker.addNickToChannel(nick, channel);
313 forEach(prefixes, function(p) {
314 self.addPrefix(nc, p);
315 });
316 });
317 }
318
319 this.disconnected = function() {
320 for(var x in this.parent.channels) {
321 ui.closeWindow(x);
322 }
323
324 self.tracker = undefined;
325
326 newServerLine("DISCONNECT");
327 self.disconnect();
328 }
329
330 this.supported = function(key, value) {
331 if(key == "PREFIX") {
332 var l = (value.length - 2) / 2;
333
334 self.modeprefixes = value.substr(1, l);
335 self.prefixes = value.substr(l + 2, l);
336 }
337 }
338
339 this.connected = function() {
340 newServerLine("CONNECT");
341 }
342
343 this.serverError = function(message) {
344 newServerLine("ERROR", {"m": message});
345 }
346
347 this.parent = new BaseIRCClient(nickname, this);
348 this.commandparser = new CommandParser(ui, this.parent.send);
349 ui.send = this.commandparser.dispatch;
350 ui.getNickname = function() {
351 return self.nickname;
352 }
353
354 this.connect = this.parent.connect;
355 this.disconnect = this.parent.disconnect;
356 }