root/trunk/Models/JVBuddy.m

Revision 3511, 20.9 kB (checked in by timothy, 2 years ago)

Buddy list clean up.

Line 
1 #import "JVBuddy.h"
2 #import "MVConnectionsController.h"
3
4 #import <ChatCore/NSStringAdditions.h>
5
6 NSString *JVBuddyCameOnlineNotification = @"JVBuddyCameOnlineNotification";
7 NSString *JVBuddyWentOfflineNotification = @"JVBuddyWentOfflineNotification";
8
9 NSString *JVBuddyUserCameOnlineNotification = @"JVBuddyUserCameOnlineNotification";
10 NSString *JVBuddyUserWentOfflineNotification = @"JVBuddyUserWentOfflineNotification";
11 NSString *JVBuddyUserStatusChangedNotification = @"JVBuddyUserStatusChangedNotification";
12 NSString *JVBuddyUserIdleTimeUpdatedNotification = @"JVBuddyUserIdleTimeUpdatedNotification";
13
14 NSString *JVBuddyActiveUserChangedNotification = @"JVBuddyActiveUserChangedNotification";
15
16 static JVBuddyName _mainPreferredName = JVBuddyFullName;
17
18 @implementation JVBuddy
19 + (JVBuddyName) preferredName {
20         return _mainPreferredName;
21 }
22
23 + (void) setPreferredName:(JVBuddyName) preferred {
24         _mainPreferredName = preferred;
25 }
26
27 #pragma mark -
28
29 - (id) init {
30         if( ( self = [super init] ) ) {
31                 _rules = [[NSMutableArray allocWithZone:nil] initWithCapacity:5];
32                 _users = [[NSMutableSet allocWithZone:nil] initWithCapacity:5];
33                 _uniqueIdentifier = [[NSString locallyUniqueString] retain];
34
35                 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _registerWithConnection: ) name:MVChatConnectionDidConnectNotification object:nil];
36                 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _disconnected: ) name:MVChatConnectionDidDisconnectNotification object:nil];
37         }
38
39         return self;
40 }
41
42 - (id) initWithDictionaryRepresentation:(NSDictionary *) dictionary {
43         if( ( self = [self init] ) ) {
44                 NSData *data = [dictionary objectForKey:@"picture"];
45                 if( [data isKindOfClass:[NSData class]] && [data length] )
46                         _picture = [[NSKeyedUnarchiver unarchiveObjectWithData:data] retain];
47
48                 NSString *string = [dictionary objectForKey:@"firstName"];
49                 if( [string isKindOfClass:[NSString class]] )
50                         _firstName = [string copyWithZone:nil];
51
52                 string = [dictionary objectForKey:@"lastName"];
53                 if( [string isKindOfClass:[NSString class]] )
54                         _lastName = [string copyWithZone:nil];
55
56                 string = [dictionary objectForKey:@"primaryEmail"];
57                 if( [string isKindOfClass:[NSString class]] )
58                         _primaryEmail = [string copyWithZone:nil];
59
60                 string = [dictionary objectForKey:@"givenNickname"];
61                 if( [string isKindOfClass:[NSString class]] )
62                         _givenNickname = [string copyWithZone:nil];
63
64                 string = [dictionary objectForKey:@"speechVoice"];
65                 if( [string isKindOfClass:[NSString class]] )
66                         _speechVoice = [string copyWithZone:nil];
67
68                 string = [dictionary objectForKey:@"uniqueIdentifier"];
69                 if( [string isKindOfClass:[NSString class]] ) {
70                         [_uniqueIdentifier release];
71                         _uniqueIdentifier = [string copyWithZone:nil];
72                 }
73
74                 if( ! [_uniqueIdentifier length] ) {
75                         [_uniqueIdentifier release];
76                         _uniqueIdentifier = [[NSString locallyUniqueString] retain];
77                 }
78
79                 string = [dictionary objectForKey:@"addressBookPersonRecord"];
80                 if( [string isKindOfClass:[NSString class]] )
81                         _person = [[[ABAddressBook sharedAddressBook] recordForUniqueId:string] retain];
82
83                 NSEnumerator *enumerator = [[dictionary objectForKey:@"rules"] objectEnumerator];
84                 NSDictionary *ruleDictionary = nil;
85                 while( ( ruleDictionary = [enumerator nextObject] ) ) {
86                         MVChatUserWatchRule *rule = [[MVChatUserWatchRule allocWithZone:nil] initWithDictionaryRepresentation:ruleDictionary];
87                         if( rule ) [self addWatchRule:rule];
88                         [rule release];
89                 }
90         }
91
92         return self;
93 }
94
95 - (void) dealloc {
96         [self unregisterWithConnections];
97
98         [[NSNotificationCenter defaultCenter] removeObserver:self];
99
100         [_person release];
101         [_rules release];
102         [_users release];
103         [_activeUser release];
104         [_picture release];
105         [_firstName release];
106         [_lastName release];
107         [_primaryEmail release];
108         [_givenNickname release];
109         [_speechVoice release];
110         [_uniqueIdentifier release];
111
112         _person = nil;
113         _users = nil;
114         _rules = nil;
115         _activeUser = nil;
116         _picture = nil;
117         _firstName = nil;
118         _lastName = nil;
119         _primaryEmail = nil;
120         _givenNickname = nil;
121         _speechVoice = nil;
122         _uniqueIdentifier = nil;
123
124         [super dealloc];
125 }
126
127 #pragma mark -
128
129 - (NSDictionary *) dictionaryRepresentation {
130         NSMutableDictionary *dictionary = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:8];
131
132         NSEnumerator *enumerator = [_rules objectEnumerator];
133         NSMutableArray *rules = [[NSMutableArray allocWithZone:nil] initWithCapacity:[_rules count]];
134         MVChatUserWatchRule *rule = nil;
135
136         while( ( rule = [enumerator nextObject] ) ) {
137                 NSDictionary *dictRep = [rule dictionaryRepresentation];
138                 if( dictRep ) [rules addObject:dictRep];
139         }
140
141         [dictionary setObject:rules forKey:@"rules"];
142         [rules release];
143
144         if( _picture ) {
145                 NSData *imageData = [NSKeyedArchiver archivedDataWithRootObject:_picture];
146                 if( imageData ) [dictionary setObject:imageData forKey:@"picture"];
147         }
148
149         if( _firstName )
150                 [dictionary setObject:_firstName forKey:@"firstName"];
151
152         if( _lastName )
153                 [dictionary setObject:_lastName forKey:@"lastName"];
154
155         if( _primaryEmail )
156                 [dictionary setObject:_primaryEmail forKey:@"primaryEmail"];
157
158         if( _givenNickname )
159                 [dictionary setObject:_givenNickname forKey:@"givenNickname"];
160
161         if( _speechVoice )
162                 [dictionary setObject:_speechVoice forKey:@"speechVoice"];
163
164         if( _uniqueIdentifier )
165                 [dictionary setObject:_uniqueIdentifier forKey:@"uniqueIdentifier"];
166
167         if( _person && [_person uniqueId] )
168                 [dictionary setObject:[_person uniqueId] forKey:@"addressBookPersonRecord"];
169
170         return [dictionary autorelease];
171 }
172
173 #pragma mark -
174
175 - (void) registerWithConnection:(MVChatConnection *) connection {
176         NSEnumerator *enumerator = [_rules objectEnumerator];
177         MVChatUserWatchRule *rule = nil;
178
179         while( ( rule = [enumerator nextObject] ) ) {
180                 if( [[rule applicableServerDomains] count] ) {
181                         NSEnumerator *domainEnumerator = [[rule applicableServerDomains] objectEnumerator];
182                         NSString *domain = nil;
183
184                         while( ( domain = [domainEnumerator nextObject] ) ) {
185                                 if( [[connection server] compare:domain options:( NSCaseInsensitiveSearch | NSLiteralSearch | NSBackwardsSearch | NSAnchoredSearch )] == NSOrderedSame ) {
186                                         [connection addChatUserWatchRule:rule];
187                                         break;
188                                 }
189                         }
190                 } else [connection addChatUserWatchRule:rule];
191         }
192 }
193
194 - (void) registerWithApplicableConnections {
195         NSEnumerator *enumerator = [_rules objectEnumerator];
196         MVChatUserWatchRule *rule = nil;
197
198         while( ( rule = [enumerator nextObject] ) ) {
199                 if( [[rule applicableServerDomains] count] ) {
200                         NSEnumerator *domainEnumerator = [[rule applicableServerDomains] objectEnumerator];
201                         NSString *domain = nil;
202
203                         while( ( domain = [domainEnumerator nextObject] ) ) {
204                                 NSEnumerator *connectionEnumerator = [[[MVConnectionsController defaultController] connectionsForServerAddress:domain] objectEnumerator];
205                                 MVChatConnection *connection = nil;
206
207                                 while( ( connection = [connectionEnumerator nextObject] ) )
208                                         [connection addChatUserWatchRule:rule];
209                         }
210                 } else {
211                         NSEnumerator *connectionEnumerator = [[[MVConnectionsController defaultController] connections] objectEnumerator];
212                         MVChatConnection *connection = nil;
213
214                         while( ( connection = [connectionEnumerator nextObject] ) )
215                                 [connection addChatUserWatchRule:rule];
216                 }
217         }
218 }
219
220 - (void) unregisterWithConnection:(MVChatConnection *) connection {
221         NSEnumerator *enumerator = [_rules objectEnumerator];
222         MVChatUserWatchRule *rule = nil;
223
224         while( ( rule = [enumerator nextObject] ) )
225                 [connection removeChatUserWatchRule:rule];
226
227         enumerator = [[[_users copy] autorelease] objectEnumerator];
228         MVChatUser *user = nil;
229
230         while( ( user = [enumerator nextObject] ) )
231                 if( [[user connection] isEqual:connection] )
232                         [_users removeObject:user];
233
234         if( [[[self activeUser] connection] isEqual:connection] )
235                 [self setActiveUser:[_users anyObject]];
236 }
237
238 - (void) unregisterWithConnections {
239         NSEnumerator *enumerator = [_rules objectEnumerator];
240         MVChatUserWatchRule *rule = nil;
241
242         while( ( rule = [enumerator nextObject] ) ) {
243                 NSEnumerator *connectionEnumerator = [[[MVConnectionsController defaultController] connections] objectEnumerator];
244                 MVChatConnection *connection = nil;
245
246                 while( ( connection = [connectionEnumerator nextObject] ) )
247                         [connection removeChatUserWatchRule:rule];
248         }
249
250         [_users removeAllObjects];
251         [self setActiveUser:nil];
252 }
253
254 #pragma mark -
255
256 - (MVChatUser *) activeUser {
257         return _activeUser;
258 }
259
260 - (void) setActiveUser:(MVChatUser *) user {
261         if( [_activeUser isEqual:user] )
262                 return;
263
264         id old = _activeUser;
265         _activeUser = [user retain];
266         [old release];
267
268         [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyActiveUserChangedNotification object:self userInfo:nil];
269 }
270
271 #pragma mark -
272
273 - (MVChatUserStatus) status {
274         return [[self activeUser] status];     
275 }
276
277 - (NSData *) awayStatusMessage {
278         return [[self activeUser] awayStatusMessage];
279 }
280
281 #pragma mark -
282
283 - (BOOL) isOnline {
284         return ( [_users count] > 0 );
285 }
286
287 - (NSDate *) dateConnected {
288         return [[self activeUser] dateConnected];       
289 }
290
291 - (NSDate *) dateDisconnected {
292         return [[self activeUser] dateDisconnected];   
293 }
294
295 #pragma mark -
296
297 - (NSTimeInterval) idleTime {
298         return [[self activeUser] idleTime];   
299 }
300
301 #pragma mark -
302
303 - (NSString *) displayName {
304         switch( [[self class] preferredName] ) {
305                 default:
306                 case JVBuddyFullName:
307                         if( [[self compositeName] length] )
308                                 return [self compositeName];
309                 case JVBuddyGivenNickname:
310                         if( [[self givenNickname] length] )
311                                 return [self givenNickname];
312                 case JVBuddyActiveNickname:
313                         return [self nickname];
314         }
315
316         return [self nickname];
317 }
318
319 - (NSString *) nickname {
320         return [[self activeUser] nickname];
321 }
322
323 #pragma mark -
324
325 - (NSSet *) users {
326         return _users;
327 }
328
329 #pragma mark -
330
331 - (NSArray *) watchRules {
332         return _rules;
333 }
334
335 - (void) addWatchRule:(MVChatUserWatchRule *) rule {
336         if( [_rules containsObject:rule] ) return;
337         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _ruleMatched: ) name:MVChatUserWatchRuleMatchedNotification object:rule];
338         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _ruleUserRemoved: ) name:MVChatUserWatchRuleRemovedMatchedUserNotification object:rule];
339         [_rules addObject:rule];
340 }
341
342 - (void) removeWatchRule:(MVChatUserWatchRule *) rule {
343         if( ! [_rules containsObject:rule] ) return;
344         [[NSNotificationCenter defaultCenter] removeObserver:self name:MVChatUserWatchRuleMatchedNotification object:rule];
345         [[NSNotificationCenter defaultCenter] removeObserver:self name:MVChatUserWatchRuleRemovedMatchedUserNotification object:rule];
346         [_rules removeObject:rule];
347 }
348
349 #pragma mark -
350
351 - (NSImage *) picture {
352         if( _picture )
353                 return _picture;
354         if( _person )
355                 return [[[NSImage alloc] initWithData:[_person imageData]] autorelease];
356         return nil;
357 }
358
359 - (void) setPicture:(NSImage *) picture {
360         id old = _picture;
361         _picture = [picture copyWithZone:nil];
362         [old release];
363 }
364
365 #pragma mark -
366
367 - (NSString *) compositeName {
368         NSString *firstName = [self firstName];
369         NSString *lastName = [self lastName];
370
371         if( ! [firstName length] && [lastName length] )
372                 return lastName;
373         if( [firstName length] && ! [lastName length] )
374                 return firstName;
375         if( [firstName length] && [lastName length] )
376                 return [NSString stringWithFormat:@"%@ %@", firstName, lastName];
377
378         firstName = [self givenNickname];
379         if( [firstName length] )
380                 return firstName;
381
382         return [[self activeUser] nickname];
383 }
384
385 - (NSString *) firstName {
386         if( _firstName ) return _firstName;
387         if( _person ) return [_person valueForProperty:kABFirstNameProperty];
388         return nil;
389 }
390
391 - (NSString *) lastName {
392         if( _lastName ) return _lastName;
393         if( _person ) return [_person valueForProperty:kABLastNameProperty];
394         return nil;
395 }
396
397 - (NSString *) primaryEmail {
398         if( _primaryEmail ) return _primaryEmail;
399
400         if( _person ) {
401                 ABMultiValue *value = [_person valueForProperty:kABEmailProperty];
402                 return [value valueAtIndex:[value indexForIdentifier:[value primaryIdentifier]]];
403         }
404
405         return nil;
406 }
407
408 - (NSString *) givenNickname {
409         if( _givenNickname ) return _givenNickname;
410         if( _person ) return [_person valueForProperty:kABNicknameProperty];
411         return nil;
412 }
413
414 - (NSString *) speechVoice {
415         return _speechVoice;
416 }
417
418 - (NSString *) uniqueIdentifier {
419         return _uniqueIdentifier;
420 }
421
422 #pragma mark -
423
424 - (void) setFirstName:(NSString *) name {
425         id old = _firstName;
426         _firstName = [name copyWithZone:nil];
427         [old release];
428 }
429
430 - (void) setLastName:(NSString *) name {
431         id old = _lastName;
432         _lastName = [name copyWithZone:nil];
433         [old release];
434 }
435
436 - (void) setPrimaryEmail:(NSString *) email {
437         id old = _primaryEmail;
438         _primaryEmail = [email copyWithZone:nil];
439         [old release];
440 }
441
442 - (void) setGivenNickname:(NSString *) name {
443         id old = _givenNickname;
444         _givenNickname = [name copyWithZone:nil];
445         [old release];
446 }
447
448 - (void) setSpeechVoice:(NSString *) voice {
449         id old = _speechVoice;
450         _speechVoice = [voice copyWithZone:nil];
451         [old release];
452 }
453
454 #pragma mark -
455
456 - (ABPerson *) addressBookPersonRecord {
457         return _person;
458 }
459
460 - (void) setAddressBookPersonRecord:(ABPerson *) record {
461         id old = _person;
462         _person = [record retain];
463         [old release];
464 }
465
466 - (void) editInAddressBook {
467         if( ! _person ) return;
468         NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"addressbook://%@?edit", [_person uniqueId]]];
469         [[NSWorkspace sharedWorkspace] openURL:url];
470 }
471
472 - (void) viewInAddressBook {
473         if( ! _person ) return;
474         NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"addressbook://%@", [_person uniqueId]]];
475         [[NSWorkspace sharedWorkspace] openURL:url];
476 }
477
478 #pragma mark -
479 #pragma mark Comparisons
480
481 - (NSComparisonResult) availabilityCompare:(JVBuddy *) buddy {
482         unsigned int b1 = 0, b2 = 0;
483
484         if( [self status] == MVChatUserAwayStatus ) b1 = 2;
485         else if( [self status] == MVChatUserAvailableStatus ) {
486                 if( [self idleTime] >= 600. ) b1 = 1;
487                 else b1 = 0;
488         } else b1 = 3;
489
490         if( [buddy status] == MVChatUserAwayStatus ) b2 = 2;
491         else if( [buddy status] == MVChatUserAvailableStatus ) {
492                 if( [buddy idleTime] >= 600. ) b2 = 1;
493                 else b2 = 0;
494         } else b2 = 3;
495
496         if( b1 > b2 ) return NSOrderedDescending;
497         else if( b1 < b2 ) return NSOrderedAscending;
498         return [self lastNameCompare:buddy];
499 }
500
501 - (NSComparisonResult) firstNameCompare:(JVBuddy *) buddy {
502         NSComparisonResult ret = NSOrderedSame;
503         NSString *name1 = [self firstName];
504         NSString *name2 = [buddy firstName];
505
506         if( ! [name1 length] ) name1 = [self lastName];
507         if( ! [name2 length] ) name2 = [buddy lastName];
508
509         if( ! [name1 length] && [name2 length] ) return NSOrderedAscending;
510         else if( ! [name2 length] && [name1 length]  ) return NSOrderedDescending;
511
512         ret = [name1 localizedCaseInsensitiveCompare:name2];
513         if( ret != NSOrderedSame ) return ret;
514
515         name1 = [self lastName];
516         name2 = [buddy lastName];
517
518         if( ! [name1 length] && [name2 length] ) return NSOrderedAscending;
519         else if( ! [name2 length] && [name1 length]  ) return NSOrderedDescending;
520
521         return [name1 localizedCaseInsensitiveCompare:name2];
522 }
523
524 - (NSComparisonResult) lastNameCompare:(JVBuddy *) buddy {
525         NSComparisonResult ret = NSOrderedSame;
526         NSString *name1 = [self lastName];
527         NSString *name2 = [buddy lastName];
528
529         if( ! [name1 length] ) name1 = [self firstName];
530         if( ! [name2 length] ) name2 = [buddy firstName];
531
532         if( ! [name1 length] && [name2 length] ) return NSOrderedAscending;
533         else if( ! [name2 length] && [name1 length]  ) return NSOrderedDescending;
534
535         ret = [name1 localizedCaseInsensitiveCompare:name2];
536         if( ret != NSOrderedSame ) return ret;
537
538         name1 = [self firstName];
539         name2 = [buddy firstName];
540
541         if( ! [name1 length] && [name2 length] ) return NSOrderedAscending;
542         else if( ! [name2 length] && [name1 length]  ) return NSOrderedDescending;
543
544         return [name1 localizedCaseInsensitiveCompare:name2];
545 }
546
547 - (NSComparisonResult) serverCompare:(JVBuddy *) buddy {
548         NSString *server1 = [[self activeUser] serverAddress];
549         NSString *server2 = [[buddy activeUser] serverAddress];
550         NSComparisonResult ret = [server1 caseInsensitiveCompare:server2];
551         return ( ret != NSOrderedSame ? ret : [self nicknameCompare:buddy] );
552 }
553
554 - (NSComparisonResult) nicknameCompare:(JVBuddy *) buddy {
555         NSString *name1 = [[self activeUser] nickname];
556         NSString *name2 = [[buddy activeUser] nickname];
557         return [name1 caseInsensitiveCompare:name2];
558 }
559 @end
560
561 #pragma mark -
562
563 @implementation JVBuddy (JVBuddyPrivate)
564 - (void) _addUser:(MVChatUser *) user {
565         if( [_users containsObject:user] )
566                 return;
567
568         BOOL cameOnline = ! [_users count];
569         [_users addObject:user];
570
571         if( [self status] != MVChatUserAvailableStatus && [self status] != MVChatUserAwayStatus )
572                 [self setActiveUser:user];
573
574         [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyUserCameOnlineNotification object:self userInfo:[NSDictionary dictionaryWithObject:user forKey:@"user"]];
575
576         if( cameOnline )
577                 [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyCameOnlineNotification object:self userInfo:nil];
578 }
579
580 - (void) _removeUser:(MVChatUser *) user {
581         if( ! [_users containsObject:user] )
582                 return;
583
584         [_users removeObject:user];
585
586         if( [[self activeUser] isEqualToChatUser:user] )
587                 [self setActiveUser:[_users anyObject]];
588
589         [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyUserWentOfflineNotification object:self userInfo:[NSDictionary dictionaryWithObject:user forKey:@"user"]];
590
591         if( ! [_users count] )
592                 [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyWentOfflineNotification object:self userInfo:nil];
593 }
594
595 - (void) _buddyIdleUpdate:(NSNotification *) notification {
596         MVChatUser *user = [notification object];
597         NSNotification *note = [NSNotification notificationWithName:JVBuddyUserIdleTimeUpdatedNotification object:self userInfo:[NSDictionary dictionaryWithObject:user forKey:@"user"]];
598         [[NSNotificationQueue defaultQueue] enqueueNotification:note postingStyle:NSPostASAP coalesceMask:( NSNotificationCoalescingOnName | NSNotificationCoalescingOnSender ) forModes:nil];
599 }
600
601 - (void) _buddyStatusChanged:(NSNotification *) notification {
602         MVChatUser *user = [notification object];
603
604         switch( [user status] ) {
605                 case MVChatUserAvailableStatus:
606                 case MVChatUserAwayStatus:
607                         [self _addUser:user];
608                         break;
609                 case MVChatUserOfflineStatus:
610                 case MVChatUserDetachedStatus:
611                         [self _removeUser:user];
612                 default: break;
613         }
614
615         [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyUserStatusChangedNotification object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", nil]];
616 }
617
618 - (void) _registerWithConnection:(NSNotification *) notification {
619         MVChatConnection *connection = [notification object];
620         [self registerWithConnection:connection];
621 }
622
623 - (void) _disconnected:(NSNotification *) notification {
624         MVChatConnection *connection = [notification object];
625         NSEnumerator *enumerator = [[[_users copy] autorelease] objectEnumerator];
626         MVChatUser *user = nil;
627
628         while( ( user = [enumerator nextObject] ) )
629                 if( [[user connection] isEqual:connection] )
630                         [self _removeUser:user];
631 }
632
633 - (void) _ruleMatched:(NSNotification *) notification {
634         MVChatUser *user = [[notification userInfo] objectForKey:@"user"];
635
636         if( [user status] == MVChatUserAvailableStatus || [user status] == MVChatUserAwayStatus )
637                 [self _addUser:user];
638
639         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _buddyIdleUpdate: ) name:MVChatUserIdleTimeUpdatedNotification object:user];
640         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _buddyStatusChanged: ) name:MVChatUserStatusChangedNotification object:user];
641 }
642
643 - (void) _ruleUserRemoved:(NSNotification *) notification {
644         MVChatUser *user = [[notification userInfo] objectForKey:@"user"];
645
646         [[NSNotificationCenter defaultCenter] removeObserver:self name:MVChatUserIdleTimeUpdatedNotification object:user];
647         [[NSNotificationCenter defaultCenter] removeObserver:self name:MVChatUserStatusChangedNotification object:user];
648
649         [self _removeUser:user];
650 }
651 @end
652 /*
653 #pragma mark -
654
655 @implementation JVBuddy (JVBuddyScripting)
656 - (NSDictionary *) activeNicknameDictionary {
657         MVChatConnection *connection = [[MVConnectionsController defaultController] connectionForServerAddress:[[self activeNickname] host]];
658         return [NSDictionary dictionaryWithObjectsAndKeys:connection, @"connection", [[self activeNickname] user], @"nickname", nil];
659 }
660
661 - (NSArray *) nicknamesArray {
662         NSMutableArray *ret = [NSMutableArray arrayWithCapacity:[_users count]];
663         NSEnumerator *enumerator = [_users objectEnumerator];
664         NSURL *nick = nil;
665
666         while( ( nick = [enumerator nextObject] ) ) {
667                 MVChatConnection *connection = [[MVConnectionsController defaultController] connectionForServerAddress:[nick host]];
668                 if( ! connection ) continue;
669                 NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:connection, @"connection", [nick user], @"nickname", nil];
670                 [ret addObject:info];
671         }
672
673         return ret;
674 }
675
676 - (NSArray *) onlineNicknamesArray {
677         NSMutableArray *ret = [NSMutableArray arrayWithCapacity:[_users count]];
678         NSEnumerator *enumerator = [_users objectEnumerator];
679         NSURL *nick = nil;
680
681         while( ( nick = [enumerator nextObject] ) ) {
682                 MVChatConnection *connection = [[MVConnectionsController defaultController] connectionForServerAddress:[nick host]];
683                 if( ! connection ) continue;
684                 NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:connection, @"connection", [nick user], @"nickname", nil];
685                 [ret addObject:info];
686         }
687
688         return ret;
689 }
690
691 - (void) editInAddressBookScriptCommand:(NSScriptCommand *) command {
692         [self editInAddressBook];
693 }
694
695 - (void) viewInAddressBookScriptCommand:(NSScriptCommand *) command {
696         [self viewInAddressBook];
697 }
698 @end */
Note: See TracBrowser for help on using the browser.