1a534c338508b44aee9704e0fd5795b00a4843ef
[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 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 this.socket.on('too_many_connections', function () {
194 that.trigger("connect_fail", {reason: 'too_many_connections'});
195 });
196
197 this.socket.on('irc', function (data, callback) {
198 that.parse(data.command, data.data);
199 });
200
201 this.socket.on('kiwi', function (data, callback) {
202 that.parseKiwi(data.command, data.data);
203 });
204
205 this.socket.on('disconnect', function () {
206 that.trigger("disconnect", {});
207 console.log("_kiwi.gateway.socket.on('disconnect')");
208 });
209
210 this.socket.on('close', function () {
211 console.log("_kiwi.gateway.socket.on('close')");
212 });
213
214 this.socket.on('reconnecting', function (reconnectionDelay, reconnectionAttempts) {
215 console.log("_kiwi.gateway.socket.on('reconnecting')");
216 that.trigger("reconnecting", {delay: reconnectionDelay, attempts: reconnectionAttempts});
217 });
218
219 this.socket.on('reconnect_failed', function () {
220 console.log("_kiwi.gateway.socket.on('reconnect_failed')");
221 });
222 };
223
224
225
226 this.isConnected = function () {
227 return this.socket.socket.connected;
228 };
229
230
231
232 this.parseKiwi = function (command, data) {
233 this.trigger('kiwi:' + command, data);
234 this.trigger('kiwi', data);
235 };
236 /*
237 Events:
238 msg
239 action
240 server_connect
241 options
242 motd
243 notice
244 userlist
245 nick
246 join
247 topic
248 part
249 kick
250 quit
251 whois
252 syncchannel_redirect
253 debug
254 */
255 /**
256 * Parses the response from the server
257 */
258 this.parse = function (command, data) {
259 //console.log('gateway event', command, data);
260
261 if (command !== undefined) {
262 that.trigger('on' + command, data);
263
264 switch (command) {
265 case 'options':
266 $.each(data.options, function (name, value) {
267 switch (name) {
268 case 'CHANTYPES':
269 that.set('channel_prefix', value.join(''));
270 break;
271 case 'NETWORK':
272 that.set('name', value);
273 break;
274 case 'PREFIX':
275 that.set('user_prefixes', value);
276 break;
277 }
278 });
279 that.set('cap', data.cap);
280 break;
281
282 case 'connect':
283 if (!_kiwi.app.connections.getByConnectionId(data.server)) {
284 _kiwi.app.connections.add(new _kiwi.model.Network({connection_id: data.server}));
285 }
286 that.set('nick', data.nick);
287 break;
288
289 case 'nick':
290 if (data.nick === that.get('nick')) {
291 that.set('nick', data.newnick);
292 }
293 break;
294 /*
295 case 'sync':
296 if (_kiwi.gateway.onSync && _kiwi.gateway.syncing) {
297 _kiwi.gateway.syncing = false;
298 _kiwi.gateway.onSync(item);
299 }
300 break;
301 */
302
303 case 'kiwi':
304 this.emit('_kiwi.' + data.namespace, data.data);
305 break;
306 }
307 }
308
309
310 if (typeof data.server !== 'undefined') {
311 that.trigger('connection:' + data.server.toString(), {
312 event_name: command,
313 event_data: data
314 });
315 }
316 };
317
318 /**
319 * Sends data to the server
320 * @private
321 * @param {Object} data The data to send
322 * @param {Function} callback A callback function
323 */
324 this.sendData = function (data, callback) {
325 var data_buffer = {
326 server: _kiwi.app.connections.active_connection.get('connection_id'),
327 data: JSON.stringify(data)
328 };
329
330 this.socket.emit('irc', data_buffer, callback);
331 };
332
333 /**
334 * Sends a PRIVMSG message
335 * @param {String} target The target of the message (e.g. a channel or nick)
336 * @param {String} msg The message to send
337 * @param {Function} callback A callback function
338 */
339 this.privmsg = function (target, msg, callback) {
340 var data = {
341 method: 'privmsg',
342 args: {
343 target: target,
344 msg: msg
345 }
346 };
347
348 this.sendData(data, callback);
349 };
350
351 /**
352 * Sends a NOTICE message
353 * @param {String} target The target of the message (e.g. a channel or nick)
354 * @param {String} msg The message to send
355 * @param {Function} callback A callback function
356 */
357 this.notice = function (target, msg, callback) {
358 var data = {
359 method: 'notice',
360 args: {
361 target: target,
362 msg: msg
363 }
364 };
365
366 this.sendData(data, callback);
367 };
368
369 /**
370 * Sends a CTCP message
371 * @param {Boolean} request Indicates whether this is a CTCP request (true) or reply (false)
372 * @param {String} type The type of CTCP message, e.g. 'VERSION', 'TIME', 'PING' etc.
373 * @param {String} target The target of the message, e.g a channel or nick
374 * @param {String} params Additional paramaters
375 * @param {Function} callback A callback function
376 */
377 this.ctcp = function (request, type, target, params, callback) {
378 var data = {
379 method: 'ctcp',
380 args: {
381 request: request,
382 type: type,
383 target: target,
384 params: params
385 }
386 };
387
388 this.sendData(data, callback);
389 };
390
391 /**
392 * @param {String} target The target of the message (e.g. a channel or nick)
393 * @param {String} msg The message to send
394 * @param {Function} callback A callback function
395 */
396 this.action = function (target, msg, callback) {
397 this.ctcp(true, 'ACTION', target, msg, callback);
398 };
399
400 /**
401 * Joins a channel
402 * @param {String} channel The channel to join
403 * @param {String} key The key to the channel
404 * @param {Function} callback A callback function
405 */
406 this.join = function (channel, key, callback) {
407 var data = {
408 method: 'join',
409 args: {
410 channel: channel,
411 key: key
412 }
413 };
414
415 this.sendData(data, callback);
416 };
417
418 /**
419 * Leaves a channel
420 * @param {String} channel The channel to part
421 * @param {Function} callback A callback function
422 */
423 this.part = function (channel, callback) {
424 var data = {
425 method: 'part',
426 args: {
427 channel: channel
428 }
429 };
430
431 this.sendData(data, callback);
432 };
433
434 /**
435 * Queries or modifies a channell topic
436 * @param {String} channel The channel to query or modify
437 * @param {String} new_topic The new topic to set
438 * @param {Function} callback A callback function
439 */
440 this.topic = function (channel, new_topic, callback) {
441 var data = {
442 method: 'topic',
443 args: {
444 channel: channel,
445 topic: new_topic
446 }
447 };
448
449 this.sendData(data, callback);
450 };
451
452 /**
453 * Kicks a user from a channel
454 * @param {String} channel The channel to kick the user from
455 * @param {String} nick The nick of the user to kick
456 * @param {String} reason The reason for kicking the user
457 * @param {Function} callback A callback function
458 */
459 this.kick = function (channel, nick, reason, callback) {
460 var data = {
461 method: 'kick',
462 args: {
463 channel: channel,
464 nick: nick,
465 reason: reason
466 }
467 };
468
469 this.sendData(data, callback);
470 };
471
472 /**
473 * Disconnects us from the server
474 * @param {String} msg The quit message to send to the IRC server
475 * @param {Function} callback A callback function
476 */
477 this.quit = function (msg, callback) {
478 msg = msg || "";
479 var data = {
480 method: 'quit',
481 args: {
482 message: msg
483 }
484 };
485
486 this.sendData(data, callback);
487 };
488
489 /**
490 * Sends a string unmodified to the IRC server
491 * @param {String} data The data to send to the IRC server
492 * @param {Function} callback A callback function
493 */
494 this.raw = function (data, callback) {
495 data = {
496 method: 'raw',
497 args: {
498 data: data
499 }
500 };
501
502 this.sendData(data, callback);
503 };
504
505 /**
506 * Changes our nickname
507 * @param {String} new_nick Our new nickname
508 * @param {Function} callback A callback function
509 */
510 this.changeNick = function (new_nick, callback) {
511 var data = {
512 method: 'nick',
513 args: {
514 nick: new_nick
515 }
516 };
517
518 this.sendData(data, callback);
519 };
520
521 /**
522 * Sends data to a fellow Kiwi IRC user
523 * @param {String} target The nick of the Kiwi IRC user to send to
524 * @param {String} data The data to send
525 * @param {Function} callback A callback function
526 */
527 this.kiwi = function (target, data, callback) {
528 data = {
529 method: 'kiwi',
530 args: {
531 target: target,
532 data: data
533 }
534 };
535
536 this.sendData(data, callback);
537 };
538
539
540 // Check a nick alongside our ignore list
541 this.isNickIgnored = function (nick) {
542 var idx, list = this.get('ignore_list');
543 var pattern, regex;
544
545 for (idx = 0; idx < list.length; idx++) {
546 pattern = list[idx].replace(/([.+^$[\]\\(){}|-])/g, "\\$1")
547 .replace('*', '.*')
548 .replace('?', '.');
549
550 regex = new RegExp(pattern, 'i');
551 if (regex.test(nick)) return true;
552 }
553
554 return false;
555 }
556
557
558 return new (Backbone.Model.extend(this))(arguments);
559 };