3 _kiwi
.model
.Network
= Backbone
.Model
.extend({
7 * The name of the network
13 * The address (URL) of the network
19 * The current nickname
25 * The channel prefix for this network
31 * The user prefixes for channel owner/admin/op/voice etc. on this network
34 user_prefixes
: ['~', '&', '@', '+']
38 initialize: function () {
39 this.gateway
= _kiwi
.global
.components
.Network(this.get('connection_id'));
40 this.bindGatewayEvents();
42 // Create our panel list (tabs)
43 this.panels
= new _kiwi
.model
.PanelList([], this);
44 //this.panels.network = this;
46 // Automatically create a server tab
47 var server_panel
= new _kiwi
.model
.Server({name
: 'Server'});
48 this.panels
.add(server_panel
);
49 this.panels
.server
= this.panels
.active
= server_panel
;
53 bindGatewayEvents: function () {
54 //this.gateway.on('all', function() {console.log('ALL', this.get('connection_id'), arguments);});
56 this.gateway
.on('connect', onConnect
, this);
57 this.gateway
.on('disconnect', onDisconnect
, this);
59 this.gateway
.on('nick', function(event
) {
60 if (event
.nick
=== this.get('nick')) {
61 this.set('nick', event
.newnick
);
65 this.gateway
.on('options', onOptions
, this);
66 this.gateway
.on('motd', onMotd
, this);
67 this.gateway
.on('join', onJoin
, this);
68 this.gateway
.on('part', onPart
, this);
69 this.gateway
.on('quit', onQuit
, this);
70 this.gateway
.on('kick', onKick
, this);
71 this.gateway
.on('msg', onMsg
, this);
72 this.gateway
.on('nick', onNick
, this);
73 this.gateway
.on('ctcp_request', onCtcpRequest
, this);
74 this.gateway
.on('ctcp_response', onCtcpResponse
, this);
75 this.gateway
.on('notice', onNotice
, this);
76 this.gateway
.on('action', onAction
, this);
77 this.gateway
.on('topic', onTopic
, this);
78 this.gateway
.on('topicsetby', onTopicSetBy
, this);
79 this.gateway
.on('userlist', onUserlist
, this);
80 this.gateway
.on('userlist_end', onUserlistEnd
, this);
81 this.gateway
.on('mode', onMode
, this);
82 this.gateway
.on('whois', onWhois
, this);
83 this.gateway
.on('away', onAway
, this);
84 this.gateway
.on('list_start', onListStart
, this);
85 this.gateway
.on('irc_error', onIrcError
, this);
90 * Create panels and join the channel
91 * This will not wait for the join event to create a panel. This
92 * increases responsiveness in case of network lag
94 createAndJoinChannels: function (channels
) {
98 // Multiple channels may come as comma-delimited
99 if (typeof channels
=== 'string') {
100 channels
= channels
.split(',');
103 $.each(channels
, function (index
, channel_name_key
) {
104 // We may have a channel key so split it off
105 var spli
= channel_name_key
.trim().split(' '),
106 channel_name
= spli
[0],
107 channel_key
= spli
[1] || '';
109 // Trim any whitespace off the name
110 channel_name
= channel_name
.trim();
112 // If not a valid channel name, display a warning
113 if (!_kiwi
.app
.isChannelName(channel_name
)) {
114 that
.panels
.server
.addMsg('', channel_name
+ ' is not a valid channel name');
115 _kiwi
.app
.message
.text(channel_name
+ ' is not a valid channel name', {timeout
: 5000});
119 // Check if we have the panel already. If not, create it
120 channel
= that
.panels
.getByName(channel_name
);
122 channel
= new _kiwi
.model
.Channel({name
: channel_name
});
123 that
.panels
.add(channel
);
126 panels
.push(channel
);
128 that
.gateway
.join(channel_name
, channel_key
);
136 * Join all the open channels we have open
137 * Reconnecting to a network would typically call this.
139 rejoinAllChannels: function() {
142 this.panels
.forEach(function(panel
) {
143 if (!panel
.isChannel())
146 that
.gateway
.join(panel
.get('name'));
153 function onDisconnect(event
) {
154 $.each(this.panels
.models
, function (index
, panel
) {
155 panel
.addMsg('', 'Disconnected from the IRC network', 'action quit');
161 function onConnect(event
) {
162 var panels
, channel_names
;
164 // Update our nick with what the network gave us
165 this.set('nick', event
.nick
);
167 // If this is a re-connection then we may have some channels to re-join
168 this.rejoinAllChannels();
170 // Auto joining channels
171 if (this.auto_join
&& this.auto_join
.channel
) {
172 panels
= this.createAndJoinChannels(this.auto_join
.channel
+ ' ' + (this.auto_join
.channel_key
|| ''));
174 // Show the last channel if we have one
176 panels
[panels
.length
- 1].view
.show();
182 function onOptions(event
) {
185 $.each(event
.options
, function (name
, value
) {
188 that
.set('channel_prefix', value
.join(''));
191 that
.set('name', value
);
194 that
.set('user_prefixes', value
);
199 this.set('cap', event
.cap
);
204 function onMotd(event
) {
205 this.panels
.server
.addMsg(this.get('name'), event
.msg
, 'motd');
210 function onJoin(event
) {
211 var c
, members
, user
;
212 c
= this.panels
.getByName(event
.channel
);
214 c
= new _kiwi
.model
.Channel({name
: event
.channel
});
218 members
= c
.get('members');
219 if (!members
) return;
221 user
= new _kiwi
.model
.Member({nick
: event
.nick
, ident
: event
.ident
, hostname
: event
.hostname
});
227 function onPart(event
) {
228 var channel
, members
, user
,
231 part_options
.type
= 'part';
232 part_options
.message
= event
.message
|| '';
234 channel
= this.panels
.getByName(event
.channel
);
235 if (!channel
) return;
237 // If this is us, close the panel
238 if (event
.nick
=== this.get('nick')) {
243 members
= channel
.get('members');
244 if (!members
) return;
246 user
= members
.getByNick(event
.nick
);
249 members
.remove(user
, part_options
);
254 function onQuit(event
) {
258 quit_options
.type
= 'quit';
259 quit_options
.message
= event
.message
|| '';
261 $.each(this.panels
.models
, function (index
, panel
) {
262 if (!panel
.isChannel()) return;
264 member
= panel
.get('members').getByNick(event
.nick
);
266 panel
.get('members').remove(member
, quit_options
);
273 function onKick(event
) {
274 var channel
, members
, user
,
277 part_options
.type
= 'kick';
278 part_options
.by
= event
.nick
;
279 part_options
.message
= event
.message
|| '';
281 channel
= this.panels
.getByName(event
.channel
);
282 if (!channel
) return;
284 members
= channel
.get('members');
285 if (!members
) return;
287 user
= members
.getByNick(event
.kicked
);
290 members
.remove(user
, part_options
);
292 if (event
.kicked
=== this.get('nick')) {
299 function onMsg(event
) {
301 is_pm
= (event
.channel
== this.get('nick'));
303 // An ignored user? don't do anything with it
304 if (_kiwi
.gateway
.isNickIgnored(event
.nick
)) {
309 // If a panel isn't found for this PM, create one
310 panel
= this.panels
.getByName(event
.nick
);
312 panel
= new _kiwi
.model
.Query({name
: event
.nick
});
313 this.panels
.add(panel
);
317 // If a panel isn't found for this channel, reroute to the
319 panel
= this.panels
.getByName(event
.channel
);
321 panel
= this.panels
.server
;
325 panel
.addMsg(event
.nick
, event
.msg
);
330 function onNick(event
) {
333 $.each(this.panels
.models
, function (index
, panel
) {
334 if (panel
.get('name') == event
.nick
)
335 panel
.set('name', event
.newnick
);
337 if (!panel
.isChannel()) return;
339 member
= panel
.get('members').getByNick(event
.nick
);
341 member
.set('nick', event
.newnick
);
342 panel
.addMsg('', '== ' + event
.nick
+ ' is now known as ' + event
.newnick
, 'action nick');
349 function onCtcpRequest(event
) {
350 // An ignored user? don't do anything with it
351 if (_kiwi
.gateway
.isNickIgnored(event
.nick
)) {
355 // Reply to a TIME ctcp
356 if (event
.msg
.toUpperCase() === 'TIME') {
357 this.gateway
.ctcp(null, false, event
.type
, event
.nick
, (new Date()).toString());
363 function onCtcpResponse(event
) {
364 // An ignored user? don't do anything with it
365 if (_kiwi
.gateway
.isNickIgnored(event
.nick
)) {
369 this.panels
.server
.addMsg('[' + event
.nick
+ ']', 'CTCP ' + event
.msg
);
374 function onNotice(event
) {
375 var panel
, channel_name
;
377 // An ignored user? don't do anything with it
378 if (!event
.from_server
&& event
.nick
&& _kiwi
.gateway
.isNickIgnored(event
.nick
)) {
382 // Find a panel for the destination(channel) or who its from
383 if (!event
.from_server
) {
384 panel
= this.panels
.getByName(event
.target
) || this.panels
.getByName(event
.nick
);
386 // Forward ChanServ messages to its associated channel
387 if (event
.nick
.toLowerCase() == 'chanserv' && event
.msg
.charAt(0) == '[') {
388 channel_name
= /\[([^ \]]+)\]/gi.exec(event
.msg
);
389 if (channel_name
&& channel_name
[1]) {
390 channel_name
= channel_name
[1];
392 panel
= this.panels
.getByName(channel_name
);
397 panel
= this.panels
.server
;
400 panel
= this.panels
.server
;
403 panel
.addMsg('[' + (event
.nick
||'') + ']', event
.msg
);
405 // Show this notice to the active panel if it didn't have a set target
406 if (!event
.from_server
&& panel
=== this.panels
.server
&& !this.panels
.server
.isActive())
407 _kiwi
.app
.panels().active
.addMsg('[' + (event
.nick
||'') + ']', event
.msg
);
412 function onAction(event
) {
414 is_pm
= (event
.channel
== this.get('nick'));
416 // An ignored user? don't do anything with it
417 if (_kiwi
.gateway
.isNickIgnored(event
.nick
)) {
422 // If a panel isn't found for this PM, create one
423 panel
= this.panels
.getByName(event
.nick
);
425 panel
= new _kiwi
.model
.Channel({name
: event
.nick
});
426 this.panels
.add(panel
);
430 // If a panel isn't found for this channel, reroute to the
432 panel
= this.panels
.getByName(event
.channel
);
434 panel
= this.panels
.server
;
438 panel
.addMsg('', '* ' + event
.nick
+ ' ' + event
.msg
, 'action');
443 function onTopic(event
) {
445 c
= this.panels
.getByName(event
.channel
);
448 // Set the channels topic
449 c
.set('topic', event
.topic
);
451 // If this is the active channel, update the topic bar too
452 if (c
.get('name') === this.panels
.active
.get('name')) {
453 _kiwi
.app
.topicbar
.setCurrentTopic(event
.topic
);
459 function onTopicSetBy(event
) {
461 c
= this.panels
.getByName(event
.channel
);
464 when
= formatDate(new Date(event
.when
* 1000));
465 c
.addMsg('', 'Topic set by ' + event
.nick
+ ' at ' + when
, 'topic');
470 function onUserlist(event
) {
472 channel
= this.panels
.getByName(event
.channel
);
474 // If we didn't find a channel for this, may aswell leave
475 if (!channel
) return;
477 channel
.temp_userlist
= channel
.temp_userlist
|| [];
478 _
.each(event
.users
, function (item
) {
479 var user
= new _kiwi
.model
.Member({nick
: item
.nick
, modes
: item
.modes
});
480 channel
.temp_userlist
.push(user
);
486 function onUserlistEnd(event
) {
488 channel
= this.panels
.getByName(event
.channel
);
490 // If we didn't find a channel for this, may aswell leave
491 if (!channel
) return;
493 // Update the members list with the new list
494 channel
.get('members').reset(channel
.temp_userlist
|| []);
496 // Clear the temporary userlist
497 delete channel
.temp_userlist
;
502 function onMode(event
) {
503 var channel
, i
, prefixes
, members
, member
, find_prefix
;
505 // Build a nicely formatted string to be displayed to a regular human
506 function friendlyModeString (event_modes
, alt_target
) {
507 var modes
= {}, return_string
;
509 // If no default given, use the main event info
511 event_modes
= event
.modes
;
512 alt_target
= event
.target
;
515 // Reformat the mode object to make it easier to work with
516 _
.each(event_modes
, function (mode
){
517 var param
= mode
.param
|| alt_target
|| '';
519 // Make sure we have some modes for this param
521 modes
[param
] = {'+':'', '-':''};
524 modes
[param
][mode
.mode
[0]] += mode
.mode
.substr(1);
527 // Put the string together from each mode
529 _
.each(modes
, function (modeset
, param
) {
531 if (modeset
['+']) str
+= '+' + modeset
['+'];
532 if (modeset
['-']) str
+= '-' + modeset
['-'];
533 return_string
.push(str
+ ' ' + param
);
535 return_string
= return_string
.join(', ');
537 return return_string
;
541 channel
= this.panels
.getByName(event
.target
);
543 prefixes
= this.get('user_prefixes');
544 find_prefix = function (p
) {
545 return event
.modes
[i
].mode
[1] === p
.mode
;
547 for (i
= 0; i
< event
.modes
.length
; i
++) {
548 if (_
.any(prefixes
, find_prefix
)) {
550 members
= channel
.get('members');
552 member
= members
.getByNick(event
.modes
[i
].param
);
554 console
.log('MODE command recieved for unknown member %s on channel %s', event
.modes
[i
].param
, event
.target
);
557 if (event
.modes
[i
].mode
[0] === '+') {
558 member
.addMode(event
.modes
[i
].mode
[1]);
559 } else if (event
.modes
[i
].mode
[0] === '-') {
560 member
.removeMode(event
.modes
[i
].mode
[1]);
563 //channel.addMsg('', '== ' + event.nick + ' set mode ' + event.modes[i].mode + ' ' + event.modes[i].param, 'action mode');
566 // Channel mode being set
567 // TODO: Store this somewhere?
568 //channel.addMsg('', 'CHANNEL === ' + event.nick + ' set mode ' + event.modes[i].mode + ' on ' + event.target, 'action mode');
572 channel
.addMsg('', '== ' + event
.nick
+ ' sets mode ' + friendlyModeString(), 'action mode');
574 // This is probably a mode being set on us.
575 if (event
.target
.toLowerCase() === this.get("nick").toLowerCase()) {
576 this.panels
.server
.addMsg('', '== ' + event
.nick
+ ' set mode ' + friendlyModeString(), 'action mode');
578 console
.log('MODE command recieved for unknown target %s: ', event
.target
, event
);
585 function onWhois(event
) {
586 var logon_date
, idle_time
= '', panel
;
591 if (typeof event
.idle
!== 'undefined') {
592 idle_time
= secondsToTime(parseInt(event
.idle
, 10));
593 idle_time
= idle_time
.h
.toString().lpad(2, "0") + ':' + idle_time
.m
.toString().lpad(2, "0") + ':' + idle_time
.s
.toString().lpad(2, "0");
596 panel
= _kiwi
.app
.panels().active
;
598 panel
.addMsg(event
.nick
, event
.nick
+ ' [' + event
.nick
+ '!' + event
.ident
+ '@' + event
.host
+ '] * ' + event
.msg
, 'whois');
599 } else if (event
.chans
) {
600 panel
.addMsg(event
.nick
, 'Channels: ' + event
.chans
, 'whois');
601 } else if (event
.irc_server
) {
602 panel
.addMsg(event
.nick
, 'Connected to server: ' + event
.irc_server
, 'whois');
603 } else if (event
.msg
) {
604 panel
.addMsg(event
.nick
, event
.msg
, 'whois');
605 } else if (event
.logon
) {
606 logon_date
= new Date();
607 logon_date
.setTime(event
.logon
* 1000);
608 logon_date
= formatDate(logon_date
);
610 panel
.addMsg(event
.nick
, 'idle for ' + idle_time
+ ', signed on ' + logon_date
, 'whois');
611 } else if (event
.away_reason
) {
612 panel
.addMsg(event
.nick
, 'Away: ' + event
.away_reason
, 'whois');
614 panel
.addMsg(event
.nick
, 'idle for ' + idle_time
, 'whois');
620 function onAway(event
) {
621 $.each(this.panels
.models
, function (index
, panel
) {
622 if (!panel
.isChannel()) return;
624 member
= panel
.get('members').getByNick(event
.nick
);
626 member
.set('away', !(!event
.trailing
));
633 function onListStart(event
) {
634 var chanlist
= _kiwi
.model
.Applet
.loadOnce('kiwi_chanlist');
635 chanlist
.view
.show();
640 function onIrcError(event
) {
643 if (event
.channel
!== undefined && !(panel
= this.panels
.getByName(event
.channel
))) {
644 panel
= this.panels
.server
;
647 switch (event
.error
) {
648 case 'banned_from_channel':
649 panel
.addMsg(' ', '== You are banned from ' + event
.channel
+ '. ' + event
.reason
, 'status');
650 _kiwi
.app
.message
.text('You are banned from ' + event
.channel
+ '. ' + event
.reason
);
652 case 'bad_channel_key':
653 panel
.addMsg(' ', '== Bad channel key for ' + event
.channel
, 'status');
654 _kiwi
.app
.message
.text('Bad channel key or password for ' + event
.channel
);
656 case 'invite_only_channel':
657 panel
.addMsg(' ', '== ' + event
.channel
+ ' is invite only.', 'status');
658 _kiwi
.app
.message
.text(event
.channel
+ ' is invite only');
660 case 'channel_is_full':
661 panel
.addMsg(' ', '== ' + event
.channel
+ ' is full.', 'status');
662 _kiwi
.app
.message
.text(event
.channel
+ ' is full');
664 case 'chanop_privs_needed':
665 panel
.addMsg(' ', '== ' + event
.reason
, 'status');
666 _kiwi
.app
.message
.text(event
.reason
+ ' (' + event
.channel
+ ')');
669 tmp
= this.panels
.getByName(event
.nick
);
671 tmp
.addMsg(' ', '== ' + event
.nick
+ ': ' + event
.reason
, 'status');
673 this.panels
.server
.addMsg(' ', '== ' + event
.nick
+ ': ' + event
.reason
, 'status');
676 case 'nickname_in_use':
677 this.panels
.server
.addMsg(' ', '== The nickname ' + event
.nick
+ ' is already in use. Please select a new nickname', 'status');
678 if (this.panels
.server
!== this.panels
.active
) {
679 _kiwi
.app
.message
.text('The nickname "' + event
.nick
+ '" is already in use. Please select a new nickname');
682 // Only show the nickchange component if the controlbox is open
683 if (_kiwi
.app
.controlbox
.$el
.css('display') !== 'none') {
684 (new _kiwi
.view
.NickChangeBox()).render();
688 case 'erroneus_nickname':
689 this.panels
.server
.addMsg(' ', '== The nickname ' + event
.nick
+ ' is not valid for this network. Please select a new nickname', 'status');
690 if (this.panels
.server
!== this.panels
.active
) {
691 _kiwi
.app
.message
.text('The nickname "' + event
.nick
+ '" is not valid for this network. Please select a new nickname');
694 // Only show the nickchange component if the controlbox is open
695 if (_kiwi
.app
.controlbox
.$el
.css('display') !== 'none') {
696 (new _kiwi
.view
.NickChangeBox()).render();
700 case 'password_mismatch':
701 this.panels
.server
.addMsg(' ', '== Incorrect password given', 'status');
704 // We don't know what data contains, so don't do anything with it.
705 //_kiwi.front.tabviews.server.addMsg(null, ' ', '== ' + data, 'status');