9db724b248ef97fb9d2f1957209d222a9bdeca85
[KiwiIRC.git] / client / assets / dev / model_gateway.js
1 _kiwi.model.Gateway = function () {
2
3 // Set to a reference to this object within initialize()
4 var that = null;
5
6 this.defaults = {
7 /**
8 * The name of the network
9 * @type String
10 */
11 name: 'Server',
12
13 /**
14 * The address (URL) of the network
15 * @type String
16 */
17 address: '',
18
19 /**
20 * The current nickname
21 * @type String
22 */
23 nick: '',
24
25 /**
26 * The channel prefix for this network
27 * @type String
28 */
29 channel_prefix: '#',
30
31 /**
32 * The user prefixes for channel owner/admin/op/voice etc. on this network
33 * @type Array
34 */
35 user_prefixes: ['~', '&', '@', '+'],
36
37 /**
38 * The URL to the Kiwi server
39 * @type String
40 */
41 kiwi_server: '//kiwi',
42
43 /**
44 * List of nicks we are ignoring
45 * @type Array
46 */
47 ignore_list: []
48 };
49
50
51 this.initialize = function () {
52 that = this;
53
54 // For ease of access. The socket.io object
55 this.socket = this.get('socket');
56
57 this.applyEventHandlers();
58 };
59
60
61 this.applyEventHandlers = function () {
62 /*
63 kiwi.gateway.on('message:#channel', my_function);
64 kiwi.gateway.on('message:somenick', my_function);
65
66 kiwi.gateway.on('notice:#channel', my_function);
67 kiwi.gateway.on('action:somenick', my_function);
68
69 kiwi.gateway.on('join:#channel', my_function);
70 kiwi.gateway.on('part:#channel', my_function);
71 kiwi.gateway.on('quit', my_function);
72 */
73 var that = this;
74
75 // Some easier handler events
76 this.on('onmsg', function (event) {
77 var source,
78 is_pm = (event.channel == that.get('nick'));
79
80 source = is_pm ? event.nick : event.channel;
81
82 that.trigger('message:' + source, event);
83 that.trigger('message', event);
84
85 if (is_pm) {
86 that.trigger('pm:' + source, event);
87 that.trigger('pm', event);
88 }
89 }, this);
90
91
92 this.on('onnotice', function (event) {
93 // The notice towards a channel or a query window?
94 var source = event.target || event.nick;
95
96 this.trigger('notice:' + source, event);
97 this.trigger('notice', event);
98 }, this);
99
100
101 this.on('onaction', function (event) {
102 var source,
103 is_pm = (event.channel == that.get('nick'));
104
105 source = is_pm ? event.nick : event.channel;
106
107 that.trigger('action:' + source, event);
108
109 if (is_pm) {
110 that.trigger('action:' + source, event);
111 that.trigger('action', event);
112 }
113 }, this);
114
115
116 this.on('ontopic', function (event) {
117 that.trigger('topic:' + event.channel, event);
118 that.trigger('topic', event);
119 });
120
121
122 this.on('onjoin', function (event) {
123 that.trigger('join:' + event.channel, event);
124 that.trigger('join', event);
125 });
126
127 };
128
129
130
131 /**
132 * Connects to the server
133 * @param {String} host The hostname or IP address of the IRC server to connect to
134 * @param {Number} port The port of the IRC server to connect to
135 * @param {Boolean} ssl Whether or not to connect to the IRC server using SSL
136 * @param {String} password The password to supply to the IRC server during registration
137 * @param {Function} callback A callback function to be invoked once Kiwi's server has connected to the IRC server
138 */
139 this.connect = function (host, port, ssl, password, callback) {
140 var resource;
141
142 // Work out the resource URL for socket.io
143 if (_kiwi.app.get('base_path').substr(0, 1) === '/') {
144 resource = _kiwi.app.get('base_path');
145 resource = resource.substr(1, resource.length-1);
146 resource += '/transport';
147 } else {
148 resource = _kiwi.app.get('base_path') + '/transport';
149 }
150
151 this.socket = io.connect(this.get('kiwi_server'), {
152 'resource': resource,
153
154 'try multiple transports': true,
155 'connect timeout': 3000,
156 'max reconnection attempts': 7,
157 'reconnection delay': 2000,
158 'sync disconnect on unload': false
159 });
160 this.socket.on('connect_failed', function (reason) {
161 this.socket.disconnect();
162 this.trigger("connect_fail", {reason: reason});
163 });
164
165 this.socket.on('error', function (e) {
166 console.log("_kiwi.gateway.socket.on('error')", {reason: e});
167 that.trigger("connect_fail", {reason: e});
168 });
169
170 this.socket.on('connecting', function (transport_type) {
171 console.log("_kiwi.gateway.socket.on('connecting')");
172 that.trigger("connecting");
173 });
174
175 /**
176 * Once connected to the kiwi server send the IRC connect command along
177 * with the IRC server details.
178 * A `connect` event is sent from the kiwi server once connected to the
179 * IRCD and the nick has been accepted.
180 */
181 this.socket.on('connect', function () {
182 that.newConnection({
183 nick: that.get('nick'),
184 host: host,
185 port: port,
186 ssl: ssl,
187 password: password
188 }, callback);
189 /*
190 this.emit('kiwi', {command: 'connect', nick: that.get('nick'), hostname: host, port: port, ssl: ssl, password:password}, function (err, server_num) {
191 if (!err) {
192 that.server_num = server_num;
193 console.log("_kiwi.gateway.socket.on('connect')");
194 } else {
195 console.log("_kiwi.gateway.socket.on('error')", {reason: err});
196 callback(err);
197 }
198 });
199 */
200 });
201
202 this.socket.on('too_many_connections', function () {
203 that.trigger("connect_fail", {reason: 'too_many_connections'});
204 });
205
206 this.socket.on('irc', function (data, callback) {
207 that.parse(data.command, data.data);
208 });
209
210 this.socket.on('kiwi', function (data, callback) {
211 that.parseKiwi(data.command, data.data);
212 });
213
214 this.socket.on('disconnect', function () {
215 that.trigger("disconnect", {});
216 console.log("_kiwi.gateway.socket.on('disconnect')");
217 });
218
219 this.socket.on('close', function () {
220 console.log("_kiwi.gateway.socket.on('close')");
221 });
222
223 this.socket.on('reconnecting', function (reconnectionDelay, reconnectionAttempts) {
224 console.log("_kiwi.gateway.socket.on('reconnecting')");
225 that.trigger("reconnecting", {delay: reconnectionDelay, attempts: reconnectionAttempts});
226 });
227
228 this.socket.on('reconnect_failed', function () {
229 console.log("_kiwi.gateway.socket.on('reconnect_failed')");
230 });
231 };
232
233
234
235 this.newConnection = function(connection_info, callback_fn) {
236 var that = this,
237 h = connection_info;
238
239 this.socket.emit('kiwi', {command: 'connect', nick: h.nick, hostname: h.host, port: h.port, ssl: h.ssl, password: h.password}, function (err, server_num) {
240 if (!err) {
241 // TODO: Remove this whole premature connection thing when panel code is tidied
242 if (server_num != 0 && !_kiwi.app.connections.getByConnectionId(server_num)){
243 _kiwi.app.connections.add(new _kiwi.model.Network({connection_id: server_num}));
244 }
245
246 console.log("_kiwi.gateway.socket.on('connect')");
247 callback_fn && callback_fn(err);
248
249 } else {
250 console.log("_kiwi.gateway.socket.on('error')", {reason: err});
251 callback_fn && callback_fn(err);
252 }
253 });
254 };
255
256
257
258 this.isConnected = function () {
259 return this.socket.socket.connected;
260 };
261
262
263
264 this.parseKiwi = function (command, data) {
265 this.trigger('kiwi:' + command, data);
266 this.trigger('kiwi', data);
267 };
268 /*
269 Events:
270 msg
271 action
272 server_connect
273 options
274 motd
275 notice
276 userlist
277 nick
278 join
279 topic
280 part
281 kick
282 quit
283 whois
284 syncchannel_redirect
285 debug
286 */
287 /**
288 * Parses the response from the server
289 */
290 this.parse = function (command, data) {
291 //console.log('gateway event', command, data);
292
293 if (command !== undefined) {
294 that.trigger('on' + command, data);
295
296 switch (command) {
297 case 'options':
298 $.each(data.options, function (name, value) {
299 switch (name) {
300 case 'CHANTYPES':
301 that.set('channel_prefix', value.join(''));
302 break;
303 case 'NETWORK':
304 that.set('name', value);
305 break;
306 case 'PREFIX':
307 that.set('user_prefixes', value);
308 break;
309 }
310 });
311 that.set('cap', data.cap);
312 break;
313
314 case 'connect':
315 that.set('nick', data.nick);
316 break;
317
318 case 'nick':
319 if (data.nick === that.get('nick')) {
320 that.set('nick', data.newnick);
321 }
322 break;
323 /*
324 case 'sync':
325 if (_kiwi.gateway.onSync && _kiwi.gateway.syncing) {
326 _kiwi.gateway.syncing = false;
327 _kiwi.gateway.onSync(item);
328 }
329 break;
330 */
331
332 case 'kiwi':
333 this.emit('_kiwi.' + data.namespace, data.data);
334 break;
335 }
336 }
337
338
339 if (typeof data.server !== 'undefined') {
340 that.trigger('connection:' + data.server.toString(), {
341 event_name: command,
342 event_data: data
343 });
344 }
345 };
346
347 /**
348 * Sends data to the server
349 * @private
350 * @param {Object} data The data to send
351 * @param {Function} callback A callback function
352 */
353 this.sendData = function (data, callback) {
354 var data_buffer = {
355 server: _kiwi.app.connections.active_connection.get('connection_id'),
356 data: JSON.stringify(data)
357 };
358
359 this.socket.emit('irc', data_buffer, callback);
360 };
361
362 /**
363 * Sends a PRIVMSG message
364 * @param {String} target The target of the message (e.g. a channel or nick)
365 * @param {String} msg The message to send
366 * @param {Function} callback A callback function
367 */
368 this.privmsg = function (target, msg, callback) {
369 var data = {
370 method: 'privmsg',
371 args: {
372 target: target,
373 msg: msg
374 }
375 };
376
377 this.sendData(data, callback);
378 };
379
380 /**
381 * Sends a NOTICE message
382 * @param {String} target The target of the message (e.g. a channel or nick)
383 * @param {String} msg The message to send
384 * @param {Function} callback A callback function
385 */
386 this.notice = function (target, msg, callback) {
387 var data = {
388 method: 'notice',
389 args: {
390 target: target,
391 msg: msg
392 }
393 };
394
395 this.sendData(data, callback);
396 };
397
398 /**
399 * Sends a CTCP message
400 * @param {Boolean} request Indicates whether this is a CTCP request (true) or reply (false)
401 * @param {String} type The type of CTCP message, e.g. 'VERSION', 'TIME', 'PING' etc.
402 * @param {String} target The target of the message, e.g a channel or nick
403 * @param {String} params Additional paramaters
404 * @param {Function} callback A callback function
405 */
406 this.ctcp = function (request, type, target, params, callback) {
407 var data = {
408 method: 'ctcp',
409 args: {
410 request: request,
411 type: type,
412 target: target,
413 params: params
414 }
415 };
416
417 this.sendData(data, callback);
418 };
419
420 /**
421 * @param {String} target The target of the message (e.g. a channel or nick)
422 * @param {String} msg The message to send
423 * @param {Function} callback A callback function
424 */
425 this.action = function (target, msg, callback) {
426 this.ctcp(true, 'ACTION', target, msg, callback);
427 };
428
429 /**
430 * Joins a channel
431 * @param {String} channel The channel to join
432 * @param {String} key The key to the channel
433 * @param {Function} callback A callback function
434 */
435 this.join = function (channel, key, callback) {
436 var data = {
437 method: 'join',
438 args: {
439 channel: channel,
440 key: key
441 }
442 };
443
444 this.sendData(data, callback);
445 };
446
447 /**
448 * Leaves a channel
449 * @param {String} channel The channel to part
450 * @param {Function} callback A callback function
451 */
452 this.part = function (channel, callback) {
453 var data = {
454 method: 'part',
455 args: {
456 channel: channel
457 }
458 };
459
460 this.sendData(data, callback);
461 };
462
463 /**
464 * Queries or modifies a channell topic
465 * @param {String} channel The channel to query or modify
466 * @param {String} new_topic The new topic to set
467 * @param {Function} callback A callback function
468 */
469 this.topic = function (channel, new_topic, callback) {
470 var data = {
471 method: 'topic',
472 args: {
473 channel: channel,
474 topic: new_topic
475 }
476 };
477
478 this.sendData(data, callback);
479 };
480
481 /**
482 * Kicks a user from a channel
483 * @param {String} channel The channel to kick the user from
484 * @param {String} nick The nick of the user to kick
485 * @param {String} reason The reason for kicking the user
486 * @param {Function} callback A callback function
487 */
488 this.kick = function (channel, nick, reason, callback) {
489 var data = {
490 method: 'kick',
491 args: {
492 channel: channel,
493 nick: nick,
494 reason: reason
495 }
496 };
497
498 this.sendData(data, callback);
499 };
500
501 /**
502 * Disconnects us from the server
503 * @param {String} msg The quit message to send to the IRC server
504 * @param {Function} callback A callback function
505 */
506 this.quit = function (msg, callback) {
507 msg = msg || "";
508 var data = {
509 method: 'quit',
510 args: {
511 message: msg
512 }
513 };
514
515 this.sendData(data, callback);
516 };
517
518 /**
519 * Sends a string unmodified to the IRC server
520 * @param {String} data The data to send to the IRC server
521 * @param {Function} callback A callback function
522 */
523 this.raw = function (data, callback) {
524 data = {
525 method: 'raw',
526 args: {
527 data: data
528 }
529 };
530
531 this.sendData(data, callback);
532 };
533
534 /**
535 * Changes our nickname
536 * @param {String} new_nick Our new nickname
537 * @param {Function} callback A callback function
538 */
539 this.changeNick = function (new_nick, callback) {
540 var data = {
541 method: 'nick',
542 args: {
543 nick: new_nick
544 }
545 };
546
547 this.sendData(data, callback);
548 };
549
550 /**
551 * Sends data to a fellow Kiwi IRC user
552 * @param {String} target The nick of the Kiwi IRC user to send to
553 * @param {String} data The data to send
554 * @param {Function} callback A callback function
555 */
556 this.kiwi = function (target, data, callback) {
557 data = {
558 method: 'kiwi',
559 args: {
560 target: target,
561 data: data
562 }
563 };
564
565 this.sendData(data, callback);
566 };
567
568
569 // Check a nick alongside our ignore list
570 this.isNickIgnored = function (nick) {
571 var idx, list = this.get('ignore_list');
572 var pattern, regex;
573
574 for (idx = 0; idx < list.length; idx++) {
575 pattern = list[idx].replace(/([.+^$[\]\\(){}|-])/g, "\\$1")
576 .replace('*', '.*')
577 .replace('?', '.');
578
579 regex = new RegExp(pattern, 'i');
580 if (regex.test(nick)) return true;
581 }
582
583 return false;
584 }
585
586
587 return new (Backbone.Model.extend(this))(arguments);
588 };