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