Changeset 3498

Show
Ignore:
Timestamp:
12/28/06 16:18:57 (2 years ago)
Author:
timothy
Message:

Greatly improved the Buddy List to quickly report users and work after reconnecting.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Chat Core.exp

    r3496 r3498  
    8080_MVChatUserAttributeUpdatedNotification 
    8181_MVChatUserWatchRuleMatchedNotification 
     82_MVChatUserWatchRuleRemovedMatchedUserNotification 
    8283_MVDownloadFileTransferOfferNotification 
    8384_MVFileTransferStartedNotification 
  • trunk/Chat Core/MVChatConnection.h

    r3496 r3498  
    7272extern NSString *MVChatConnectionSelfAwayStatusChangedNotification; 
    7373 
    74 extern NSString *MVChatConnectionWatchedUserOnlineNotification; 
    75 extern NSString *MVChatConnectionWatchedUserOfflineNotification; 
    76  
    7774extern NSString *MVChatConnectionNicknameAcceptedNotification; 
    7875extern NSString *MVChatConnectionNicknameRejectedNotification; 
  • trunk/Chat Core/MVChatConnection.m

    r3496 r3498  
    671671- (void) addChatUserWatchRule:(MVChatUserWatchRule *) rule { 
    672672        NSParameterAssert( rule != nil ); 
     673 
    673674        if( ! _chatUserWatchRules ) 
    674675                _chatUserWatchRules = [[NSMutableSet allocWithZone:nil] initWithCapacity:10]; 
     676 
    675677        @synchronized( _chatUserWatchRules ) { 
    676678                if( ! [_chatUserWatchRules containsObject:rule] ) 
     
    681683- (void) removeChatUserWatchRule:(MVChatUserWatchRule *) rule { 
    682684        NSParameterAssert( rule != nil ); 
     685 
     686        [rule removeMatchedUsersForConnection:self]; 
     687 
    683688        @synchronized( _chatUserWatchRules ) { 
    684689                [_chatUserWatchRules removeObject:rule]; 
     
    919924} 
    920925 
    921 - (void) _sendPossibleOnlineNotificationForUser:(MVChatUser *) user { 
    922         if( [user _onlineNotificationSent] ) return; 
    923         if( [user isWatched] || [self _watchRulesMatchingUser:user] ) { 
    924                 [user _setOnlineNotificationSent:YES]; 
    925                 [user _setDateDisconnected:nil]; 
    926                 if( [user status] != MVChatUserAwayStatus ) 
    927                         [user _setStatus:MVChatUserAvailableStatus]; 
    928                 if( ! [user dateDisconnected] ) 
    929                         [user _setDateConnected:[NSDate date]]; 
    930  
    931                 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatConnectionWatchedUserOnlineNotification object:user userInfo:nil]; 
    932         } 
    933 
    934  
    935 - (void) _sendPossibleOfflineNotificationForUser:(MVChatUser *) user { 
    936         if( ! [user _onlineNotificationSent] ) return; 
    937         if( [user isWatched] ) { 
    938                 [user _setOnlineNotificationSent:NO]; 
    939                 [user _setWatched:NO]; 
    940  
    941                 if( ! [user dateDisconnected] ) 
    942                         [user _setDateDisconnected:[NSDate date]]; 
    943                 [user _setStatus:MVChatUserOfflineStatus]; 
    944  
     926- (void) _markUserAsOnline:(MVChatUser *) user { 
     927        [user _setDateDisconnected:nil]; 
     928 
     929        if( ! [user dateConnected] ) 
     930                [user _setDateConnected:[NSDate date]]; 
     931 
     932        if( [user status] != MVChatUserAwayStatus ) 
     933                [user _setStatus:MVChatUserAvailableStatus]; 
     934 
     935        [self _watchRulesMatchingUser:user]; 
     936
     937 
     938- (void) _markUserAsOffline:(MVChatUser *) user { 
     939        if( ! [user dateDisconnected] && [user dateConnected] ) 
     940                [user _setDateDisconnected:[NSDate date]]; 
     941 
     942        if( [user status] != MVChatUserOfflineStatus ) { 
    945943                [user retain]; // retain since removeMatchedUser might hold the last reference 
    946944 
     
    952950                } 
    953951 
    954                 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatConnectionWatchedUserOfflineNotification object:user userInfo:nil]; 
     952                [user _setStatus:MVChatUserOfflineStatus]; 
    955953 
    956954                [user release]; 
  • trunk/Chat Core/MVChatConnectionPrivate.h

    r3349 r3498  
    2121 
    2222- (unsigned int) _watchRulesMatchingUser:(MVChatUser *) user; 
    23 - (void) _sendPossibleOnlineNotificationForUser:(MVChatUser *) user; 
    24 - (void) _sendPossibleOfflineNotificationForUser:(MVChatUser *) user; 
     23- (void) _markUserAsOnline:(MVChatUser *) user; 
     24- (void) _markUserAsOffline:(MVChatUser *) user; 
    2525@end 
  • trunk/Chat Core/MVChatUser.h

    r3456 r3498  
    7676        BOOL _identified : 1; 
    7777        BOOL _serverOperator : 1; 
    78         BOOL _watched : 1; 
    7978        BOOL _onlineNotificationSent : 1; 
    8079} 
     
    161160- (BOOL) isIdentified; 
    162161- (BOOL) isServerOperator; 
    163 - (BOOL) isWatched; 
    164162 
    165163- (BOOL) isEqual:(id) object; 
  • trunk/Chat Core/MVChatUser.m

    r3457 r3498  
    165165@property(readonly, getter=isIdentified) BOOL identified; 
    166166@property(readonly, getter=isServerOperator) BOOL serverOperator; 
    167 @property(readonly, getter=isWatched) BOOL watched; 
    168167#endif 
    169168 
     
    174173- (BOOL) isServerOperator { 
    175174        return _serverOperator; 
    176 } 
    177  
    178 - (BOOL) isWatched { 
    179         return _watched; 
    180175} 
    181176 
     
    510505} 
    511506 
    512 - (void) _setWatched:(BOOL) isWatched { 
    513         _watched = isWatched; 
    514 } 
    515  
    516507- (void) _setIdleTime:(NSTimeInterval) time { 
    517508        _idleTime = time; 
  • trunk/Chat Core/MVChatUserPrivate.h

    r3420 r3498  
    1212- (void) _setServerOperator:(BOOL) operator; 
    1313- (void) _setIdentified:(BOOL) identified; 
    14 - (void) _setWatched:(BOOL) watched; 
    1514- (void) _setIdleTime:(NSTimeInterval) time; 
    1615- (void) _setStatus:(MVChatUserStatus) status; 
  • trunk/Chat Core/MVChatUserWatchRule.h

    r3455 r3498  
    11@class MVChatUser; 
     2@class MVChatConnection; 
    23@class AGRegex; 
    34 
    45extern NSString *MVChatUserWatchRuleMatchedNotification; 
     6extern NSString *MVChatUserWatchRuleRemovedMatchedUserNotification; 
    57 
    68@interface MVChatUserWatchRule : NSObject <NSCopying> { 
     
    2527- (BOOL) matchChatUser:(MVChatUser *) user; 
    2628- (void) removeMatchedUser:(MVChatUser *) user; 
     29- (void) removeMatchedUsersForConnection:(MVChatConnection *) connection; 
    2730 
    2831#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 
  • trunk/Chat Core/MVChatUserWatchRule.m

    r3484 r3498  
    77 
    88NSString *MVChatUserWatchRuleMatchedNotification = @"MVChatUserWatchRuleMatchedNotification"; 
     9NSString *MVChatUserWatchRuleRemovedMatchedUserNotification = @"MVChatUserWatchRuleRemovedMatchedUserNotification"; 
    910 
    1011@implementation MVChatUserWatchRule 
     
    2324} 
    2425 
     26- (void) dealloc { 
     27        [_matchedChatUsers release]; 
     28        [_nickname release]; 
     29        [_nicknameRegex release]; 
     30        [_realName release]; 
     31        [_realNameRegex release]; 
     32        [_username release]; 
     33        [_usernameRegex release]; 
     34        [_address release]; 
     35        [_addressRegex release]; 
     36        [_publicKey release]; 
     37        [_applicableServerDomains release]; 
     38 
     39        _matchedChatUsers = nil; 
     40        _nickname = nil; 
     41        _nicknameRegex = nil; 
     42        _realName = nil; 
     43        _realNameRegex = nil; 
     44        _username = nil; 
     45        _usernameRegex = nil; 
     46        _address = nil; 
     47        _addressRegex = nil; 
     48        _publicKey = nil; 
     49        _applicableServerDomains = nil; 
     50 
     51        [super dealloc]; 
     52} 
     53 
    2554- (id) copyWithZone:(NSZone *) zone { 
    2655        MVChatUserWatchRule *copy = [[MVChatUserWatchRule allocWithZone:zone] init]; 
     
    78107        if( ! user ) return NO; 
    79108 
     109        if( ! _matchedChatUsers ) 
     110                _matchedChatUsers = [[NSMutableSet allocWithZone:nil] initWithCapacity:10]; 
     111 
    80112        @synchronized( _matchedChatUsers ) { 
    81113                if( [_matchedChatUsers containsObject:user] ) 
     
    108140        @synchronized( _matchedChatUsers ) { 
    109141                if( ! [_matchedChatUsers containsObject:user] ) { 
    110                         [user _setWatched:YES]; 
    111142                        [_matchedChatUsers addObject:user]; 
    112143                        [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatUserWatchRuleMatchedNotification object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", nil]]; 
     
    125156- (void) removeMatchedUser:(MVChatUser *) user { 
    126157        @synchronized( _matchedChatUsers ) { 
    127                 [_matchedChatUsers removeObject:user]; 
     158                if( [_matchedChatUsers containsObject:user] ) { 
     159                        [user retain]; 
     160                        [_matchedChatUsers removeObject:user]; 
     161                        [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatUserWatchRuleRemovedMatchedUserNotification object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", nil]]; 
     162                        [user release]; 
     163                } 
     164        } 
     165
     166 
     167- (void) removeMatchedUsersForConnection:(MVChatConnection *) connection { 
     168        @synchronized( _matchedChatUsers ) { 
     169                NSEnumerator *enumerator = [[[_matchedChatUsers copy] autorelease] objectEnumerator]; 
     170                MVChatUser *user = nil; 
     171 
     172                while( ( user = [enumerator nextObject] ) ) { 
     173                        if( [[user connection] isEqual:connection] ) { 
     174                                [user retain]; 
     175                                [_matchedChatUsers removeObject:user]; 
     176                                [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatUserWatchRuleRemovedMatchedUserNotification object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", nil]]; 
     177                                [user release]; 
     178                        } 
     179                } 
    128180        } 
    129181} 
  • trunk/Chat Core/MVIRCChatConnection.h

    r3228 r3498  
    1616        NSMutableArray *_sendQueue; 
    1717        NSMutableDictionary *_knownUsers; 
    18         NSMutableSet *_matchedUsers; 
    1918        NSMutableSet *_pendingWhoisUsers; 
    2019        NSMutableSet *_fileTransfers; 
  • trunk/Chat Core/MVIRCChatConnection.m

    r3483 r3498  
    139139        [_queueWait release]; 
    140140        [_lastCommand release]; 
    141         [_matchedUsers release]; 
    142141        [_pendingWhoisUsers release]; 
    143142        [_roomPrefixes release]; 
     
    163162        _queueWait = nil; 
    164163        _lastCommand = nil; 
    165         _matchedUsers = nil; 
    166164        _pendingWhoisUsers = nil; 
    167165        _roomPrefixes = nil; 
     
    482480                        if( _watchCommandSupported ) [self sendRawMessageWithFormat:@"WATCH +%@", [rule nickname]]; 
    483481                        else [self sendRawMessageWithFormat:@"ISON %@", [rule nickname]]; 
     482                } 
     483        } else { 
     484                @synchronized( _knownUsers ) { 
     485                        NSEnumerator *enumerator = [_knownUsers objectEnumerator]; 
     486                        MVChatUser *user = nil; 
     487                        while( ( user = [enumerator nextObject] ) ) 
     488                                [rule matchChatUser:user]; 
    484489                } 
    485490        } 
     
    686691        [old release]; 
    687692 
    688         old = _matchedUsers; 
    689         _matchedUsers = nil; 
    690         [old release]; 
    691  
    692693        old = _pendingWhoisUsers; 
    693694        _pendingWhoisUsers = nil; 
     
    708709 
    709710                [self performSelectorOnMainThread:@selector( _didDisconnect ) withObject:nil waitUntilDone:NO]; 
     711        } 
     712 
     713        @synchronized( _knownUsers ) { 
     714                NSEnumerator *enumerator = [_knownUsers objectEnumerator]; 
     715                MVChatUser *user = nil; 
     716 
     717                while( ( user = [enumerator nextObject] ) ) 
     718                        [user _setStatus:MVChatUserUnknownStatus]; 
     719        } 
     720 
     721        @synchronized( _chatUserWatchRules ) { 
     722                NSEnumerator *enumerator = [_chatUserWatchRules objectEnumerator]; 
     723                MVChatUserWatchRule *rule = nil; 
     724                while( ( rule = [enumerator nextObject] ) ) 
     725                        [rule removeMatchedUsersForConnection:self]; 
    710726        } 
    711727} 
     
    11151131#pragma mark - 
    11161132 
    1117 - (unsigned int) _watchRulesMatchingUser:(MVChatUser *) user { 
    1118         if( ! _matchedUsers ) 
    1119                 _matchedUsers = [[NSMutableSet allocWithZone:nil] initWithCapacity:25]; 
    1120  
    1121         unsigned int count = 0; 
    1122         @synchronized( _chatUserWatchRules ) { 
    1123                 NSEnumerator *enumerator = [_chatUserWatchRules objectEnumerator]; 
    1124                 MVChatUserWatchRule *rule = nil; 
    1125                 while( ( rule = [enumerator nextObject] ) ) { 
    1126                         if( [rule matchChatUser:user] ) { 
    1127                                 count++; 
    1128                                 @synchronized( _matchedUsers ) { 
    1129                                         [_matchedUsers addObject:user]; 
    1130                                 } 
    1131                         } 
    1132                 } 
    1133         } 
    1134  
    1135         return count; 
    1136 } 
    1137  
    1138 - (void) _sendPossibleOfflineNotificationForUser:(MVChatUser *) user { 
    1139         @synchronized( _matchedUsers ) { 
    1140                 if( [user isWatched] ) [_matchedUsers removeObject:user]; 
    1141         } 
    1142  
    1143         [super _sendPossibleOfflineNotificationForUser:user]; 
    1144 } 
    1145  
    11461133- (void) _scheduleWhoisForUser:(MVChatUser *) user { 
    11471134        if( ! _pendingWhoisUsers ) 
     
    11621149        [self performSelector:@selector( _whoisWatchedUsers ) withObject:nil afterDelay:JVWatchedUserWHOISDelay]; 
    11631150 
    1164         @synchronized( _matchedUsers ) { 
    1165                 if( ! [_matchedUsers count] ) return; // nothing to do, return and wait until the next scheduled fire 
    1166  
    1167                 NSEnumerator *enumerator = [_matchedUsers objectEnumerator]; 
    1168                 MVChatUser *user = nil; 
    1169                 while( ( user = [enumerator nextObject] ) ) 
    1170                         [self _scheduleWhoisForUser:user]; 
    1171         } 
     1151        NSMutableSet *matchedUsers = [NSMutableSet set]; 
     1152        @synchronized( _chatUserWatchRules ) { 
     1153                if( ! [_chatUserWatchRules count] ) return; // nothing to do, return and wait until the next scheduled fire 
     1154 
     1155                NSEnumerator *enumerator = [_chatUserWatchRules objectEnumerator]; 
     1156                MVChatUserWatchRule *rule = nil; 
     1157                while( ( rule = [enumerator nextObject] ) ) 
     1158                        [matchedUsers unionSet:[rule matchedChatUsers]]; 
     1159        } 
     1160 
     1161        NSEnumerator *enumerator = [matchedUsers objectEnumerator]; 
     1162        MVChatUser *user = nil; 
     1163        while( ( user = [enumerator nextObject] ) ) 
     1164                [self _scheduleWhoisForUser:user]; 
    11721165} 
    11731166 
     
    11791172        if( [_lastSentIsonNicknames count] ) return; // there is already pending ISON requests, skip this round to catch up 
    11801173 
    1181         @synchronized( _matchedUsers ) { 
    1182                 @synchronized( _chatUserWatchRules ) { 
    1183                         if( ! [_matchedUsers count] && ! [_chatUserWatchRules count] ) 
    1184                                 return; // nothing to do, return and wait until the next scheduled fire 
    1185                 } 
     1174        NSMutableSet *matchedUsers = [NSMutableSet set]; 
     1175        @synchronized( _chatUserWatchRules ) { 
     1176                if( ! [_chatUserWatchRules count] ) return; // nothing to do, return and wait until the next scheduled fire 
     1177 
     1178                NSEnumerator *enumerator = [_chatUserWatchRules objectEnumerator]; 
     1179                MVChatUserWatchRule *rule = nil; 
     1180                while( ( rule = [enumerator nextObject] ) ) 
     1181                        [matchedUsers unionSet:[rule matchedChatUsers]]; 
    11861182        } 
    11871183 
     
    11921188 
    11931189        [_lastSentIsonNicknames release]; 
    1194         _lastSentIsonNicknames = [[NSMutableSet allocWithZone:nil] initWithCapacity:[_chatUserWatchRules count]]; 
    1195  
    1196         @synchronized( _matchedUsers ) { 
    1197                 NSEnumerator *enumerator = [_matchedUsers objectEnumerator]; 
    1198                 MVChatUser *user = nil; 
    1199  
    1200                 while( ( user = [enumerator nextObject] ) ) { 
    1201                         NSString *nick = [user nickname]; 
    1202                         if( ( [nick length] + [request length] ) > 510 ) { 
    1203                                 [self sendRawMessage:request]; 
    1204                                 [request release]; 
    1205                                 _isonSentCount++; 
    1206  
    1207                                 request = [[NSMutableString allocWithZone:nil] initWithCapacity:510]; 
    1208                                 [request setString:@"ISON "]; 
    1209                         } 
    1210  
    1211                         [request appendString:nick]; 
    1212                         [request appendString:@" "]; 
    1213  
    1214                         [_lastSentIsonNicknames addObject:nick]; 
    1215                 } 
     1190        _lastSentIsonNicknames = [[NSMutableSet allocWithZone:nil] initWithCapacity:( [_chatUserWatchRules count] * 5 )]; 
     1191 
     1192        NSEnumerator *enumerator = [matchedUsers objectEnumerator]; 
     1193        MVChatUser *user = nil; 
     1194 
     1195        while( ( user = [enumerator nextObject] ) ) { 
     1196                NSString *nick = [user nickname]; 
     1197                if( ( [nick length] + [request length] ) > 510 ) { 
     1198                        [self sendRawMessage:request]; 
     1199                        [request release]; 
     1200                        _isonSentCount++; 
     1201 
     1202                        request = [[NSMutableString allocWithZone:nil] initWithCapacity:510]; 
     1203                        [request setString:@"ISON "]; 
     1204                } 
     1205 
     1206                [request appendString:nick]; 
     1207                [request appendString:@" "]; 
     1208 
     1209                [_lastSentIsonNicknames addObject:nick]; 
    12161210        } 
    12171211 
     
    12221216                while( ( rule = [enumerator nextObject] ) ) { 
    12231217                        NSString *nick = [rule nickname]; 
    1224             if( nick && ! [rule nicknameIsRegularExpression] && ! [_lastSentIsonNicknames containsObject:nick] ) {  
     1218                       if( [nick length] && ! [rule nicknameIsRegularExpression] && ! [_lastSentIsonNicknames containsObject:nick] ) {  
    12251219                                if( ( [nick length] + [request length] ) > 510 ) { 
    12261220                                        [self sendRawMessage:request]; 
     
    14541448                BOOL ctcp = ( *bytes == '\001' && [msgData length] > 2 ); 
    14551449 
    1456                 if( [sender status] != MVChatUserAwayStatus ) 
    1457                         [sender _setStatus:MVChatUserAvailableStatus]; 
    14581450                [sender _setIdleTime:0.]; 
     1451                [self _markUserAsOnline:sender]; 
    14591452 
    14601453                if( [[self chatRoomNamePrefixes] characterIsMember:[targetName characterAtIndex:0]] ) { 
     
    17571750                        [room _clearBannedUsers]; 
    17581751                } else { 
    1759                         if( [sender status] != MVChatUserAwayStatus ) 
    1760                                 [sender _setStatus:MVChatUserAvailableStatus]; 
    17611752                        [sender _setIdleTime:0.]; 
     1753                        [self _markUserAsOnline:sender]; 
    17621754                        [room _addMemberUser:sender]; 
    17631755                        [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatRoomUserJoinedNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", nil]]; 
    1764                         [self _sendPossibleOnlineNotificationForUser:sender]; 
    17651756                } 
    17661757        } 
     
    17881779                if( [sender isLocalUser] ) return; 
    17891780 
    1790                 [sender _setDateDisconnected:[NSDate date]]; 
    1791                 [sender _setStatus:MVChatUserOfflineStatus]; 
     1781                [self _markUserAsOffline:sender]; 
     1782                [_pendingWhoisUsers removeObject:sender]; 
    17921783 
    17931784                NSData *reason = [parameters objectAtIndex:0]; 
     
    18041795 
    18051796                [info release]; 
    1806  
    1807                 [self _sendPossibleOfflineNotificationForUser:sender]; 
    1808  
    1809                 [_pendingWhoisUsers removeObject:sender]; 
    18101797        } 
    18111798} 
     
    20071994- (void) _handlePingWithParameters:(NSArray *) parameters fromSender:(id) sender { 
    20081995        if( [parameters count] >= 1 ) { 
    2009                 if( [parameters count] == 1 ) [self sendRawMessageImmediatelyWithComponents:@"PONG :", [parameters objectAtIndex:0], nil]; 
     1996                if( [parameters count] == 1 ) 
     1997                        [self sendRawMessageImmediatelyWithComponents:@"PONG :", [parameters objectAtIndex:0], nil]; 
    20101998                else [self sendRawMessageImmediatelyWithComponents:@"PONG ", [parameters objectAtIndex:1], @" :", [parameters objectAtIndex:0], nil]; 
    2011                 if( [sender isKindOfClass:[MVChatUser class]] ) [self _sendPossibleOnlineNotificationForUser:sender]; 
     1999 
     2000                if( [sender isKindOfClass:[MVChatUser class]] ) 
     2001                        [self _markUserAsOnline:sender]; 
    20122002        } 
    20132003} 
     
    20212011        if( [parameters count] == 2 && [sender isKindOfClass:[MVChatUser class]] ) { 
    20222012                NSString *roomName = [self _stringFromPossibleData:[parameters objectAtIndex:1]]; 
     2013                [self _markUserAsOnline:sender]; 
    20232014                [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatRoomInvitedNotification object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", roomName, @"room", nil]]; 
    2024                 [self _sendPossibleOnlineNotificationForUser:sender]; 
    20252015        } 
    20262016} 
     
    20322022                NSString *oldIdentifier = [[sender uniqueIdentifier] retain]; 
    20332023 
    2034                 if( [sender status] != MVChatUserAwayStatus ) 
    2035                         [sender _setStatus:MVChatUserAvailableStatus]; 
    20362024                [sender _setIdleTime:0.]; 
     2025                [self _markUserAsOnline:sender]; 
    20372026 
    20382027                NSNotification *note = nil; 
     
    20592048                [oldNickname release]; 
    20602049                [oldIdentifier release]; 
    2061  
    2062                 [self _sendPossibleOnlineNotificationForUser:sender]; 
    20632050        } 
    20642051} 
     
    20802067                                if( [[user dateUpdated] timeIntervalSinceNow] < -JVWatchedUserWHOISDelay || ! [user dateUpdated] ) 
    20812068                                        [self _scheduleWhoisForUser:user]; 
    2082  
    2083                                 [self _sendPossibleOnlineNotificationForUser:user]; 
     2069                                [self _markUserAsOnline:user]; 
    20842070                                [_lastSentIsonNicknames removeObject:nick]; 
    20852071                        } 
     
    20902076                        while( ( nick = [enumerator nextObject] ) ) { 
    20912077                                MVChatUser *user = [self chatUserWithUniqueIdentifier:nick]; 
    2092                                 [self _sendPossibleOfflineNotificationForUser:user]; 
     2078                                [self _markUserAsOffline:user]; 
    20932079                        } 
    20942080 
     
    21572143                                [room _addMemberUser:member]; 
    21582144                                [room _setModes:modes forMemberUser:member]; 
     2145 
     2146                                [self _markUserAsOnline:member]; 
    21592147                        } 
    21602148 
     
    22112199                } 
    22122200 
    2213                 [self _sendPossibleOnlineNotificationForUser:member]; 
     2201                [self _markUserAsOnline:member]; 
    22142202        } 
    22152203} 
     
    22942282        if( [parameters count] == 6 ) { 
    22952283                MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; 
    2296                 [user _setServerOperator:NO]; // set these to NO now so we get the true values later in the WHOIS 
    22972284                [user _setUsername:[parameters objectAtIndex:2]]; 
    22982285                [user _setAddress:[parameters objectAtIndex:3]]; 
    22992286                [user _setRealName:[self _stringFromPossibleData:[parameters objectAtIndex:5]]]; 
    2300                 [user _setDateDisconnected:nil]; 
    2301                 [user _setAwayStatusMessage:nil]; // set this to nil, we will get it if we get a 301 
    2302  
    2303                 [self _sendPossibleOnlineNotificationForUser:user]; 
     2287                [user _setAwayStatusMessage:nil]; // set this to nil, we will get it if we get a RPL_AWAY 
     2288                [user _setServerOperator:NO]; // set this to NO now so we get the true values later in the RPL_WHOISOPERATOR 
     2289 
     2290                [self _markUserAsOnline:user]; 
    23042291        } 
    23052292} 
     
    23392326                MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; 
    23402327                [user _setDateUpdated:[NSDate date]]; 
    2341  
    2342                 if( [user status] != MVChatUserAwayStatus ) 
    2343                         [user _setStatus:MVChatUserAvailableStatus]; 
    23442328 
    23452329                [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatUserInformationUpdatedNotification object:user userInfo:nil]; 
     
    23982382        if( [parameters count] >= 2 ) { 
    23992383                MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; 
    2400                 [self _sendPossibleOfflineNotificationForUser:user]; 
     2384                [self _markUserAsOffline:user]; 
    24012385                if( [_pendingWhoisUsers containsObject:user] ) { 
    24022386                        [_pendingWhoisUsers removeObject:user]; 
     
    24102394        if( [parameters count] >= 2 ) { 
    24112395                MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; 
    2412                 [self _sendPossibleOfflineNotificationForUser:user]; 
     2396                [self _markUserAsOffline:user]; 
    24132397                if( [_pendingWhoisUsers containsObject:user] ) { 
    24142398                        [_pendingWhoisUsers removeObject:user]; 
     
    24382422                [user _setUsername:[parameters objectAtIndex:2]]; 
    24392423                [user _setAddress:[parameters objectAtIndex:3]]; 
    2440                 [user _setDateDisconnected:nil]; 
    2441  
    2442                 [self _sendPossibleOnlineNotificationForUser:user]; 
     2424 
     2425                [self _markUserAsOnline:user]; 
    24432426 
    24442427                if( [[user dateUpdated] timeIntervalSinceNow] < -JVWatchedUserWHOISDelay || ! [user dateUpdated] ) 
  • trunk/Models/JVBuddy.m

    r3491 r3498  
    227227        while( ( rule = [enumerator nextObject] ) ) 
    228228                [connection removeChatUserWatchRule:rule]; 
     229 
     230        enumerator = [[[_users copy] autorelease] objectEnumerator]; 
     231        MVChatUser *user = nil; 
     232 
     233        while( ( user = [enumerator nextObject] ) ) 
     234                if( [[user connection] isEqual:connection] ) 
     235                        [_users removeObject:user]; 
     236 
     237        if( [[[self activeUser] connection] isEqual:connection] ) 
     238                [self setActiveUser:[_users anyObject]]; 
    229239} 
    230240 
     
    240250                        [connection removeChatUserWatchRule:rule]; 
    241251        } 
     252 
     253        [_users removeAllObjects]; 
     254        [self setActiveUser:nil]; 
    242255} 
    243256 
     
    321334        if( [_rules containsObject:rule] ) return; 
    322335        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _ruleMatched: ) name:MVChatUserWatchRuleMatchedNotification object:rule]; 
     336        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _ruleUserRemoved: ) name:MVChatUserWatchRuleRemovedMatchedUserNotification object:rule]; 
    323337        [_rules addObject:rule]; 
    324338} 
     
    327341        if( ! [_rules containsObject:rule] ) return; 
    328342        [[NSNotificationCenter defaultCenter] removeObserver:self name:MVChatUserWatchRuleMatchedNotification object:rule]; 
     343        [[NSNotificationCenter defaultCenter] removeObserver:self name:MVChatUserWatchRuleRemovedMatchedUserNotification object:rule]; 
    329344        [_rules removeObject:rule]; 
    330345} 
     
    545560 
    546561@implementation JVBuddy (JVBuddyPrivate) 
    547 - (void) _buddyOnline:(NSNotification *) notification { 
    548         MVChatUser *user = [notification object]; 
    549         BOOL cameOnline = ( ! [_users count] ? YES : NO ); 
     562- (void) _addUser:(MVChatUser *) user { 
     563        if( [_users containsObject:user] ) 
     564                return; 
     565 
     566        BOOL cameOnline = ! [_users count]; 
    550567        [_users addObject:user]; 
    551568 
    552         if( [self status] != MVChatUserAvailableStatus && [self status] != MVChatUserAwayStatus ) [self setActiveUser:user]; 
    553         if( cameOnline ) [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyCameOnlineNotification object:self userInfo:nil]; 
    554 
    555  
    556 - (void) _buddyOffline:(NSNotification *) notification { 
    557         MVChatUser *user = [notification object]; 
     569        if( [self status] != MVChatUserAvailableStatus && [self status] != MVChatUserAwayStatus ) 
     570                [self setActiveUser:user]; 
     571 
     572        if( cameOnline ) 
     573                [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyCameOnlineNotification object:self userInfo:nil]; 
     574
     575 
     576- (void) _removeUser:(MVChatUser *) user { 
     577        if( ! [_users containsObject:user] ) 
     578                return; 
     579 
    558580        [_users removeObject:user]; 
    559581 
     
    561583                [self setActiveUser:[_users anyObject]]; 
    562584 
    563         if( ! [_users count] ) [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyWentOfflineNotification object:self userInfo:nil]; 
     585        if( ! [_users count] ) 
     586                [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyWentOfflineNotification object:self userInfo:nil]; 
    564587} 
    565588 
     
    572595- (void) _buddyStatusChanged:(NSNotification *) notification { 
    573596        MVChatUser *user = [notification object]; 
    574         NSNotification *note = [NSNotification notificationWithName:JVBuddyUserStatusChangedNotification object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", nil]]; 
    575         [[NSNotificationQueue defaultQueue] enqueueNotification:note postingStyle:NSPostASAP coalesceMask:( NSNotificationCoalescingOnName | NSNotificationCoalescingOnSender ) forModes:nil]; 
     597 
     598        switch( [user status] ) { 
     599                case MVChatUserAvailableStatus: 
     600                case MVChatUserAwayStatus: 
     601                        [self _addUser:user]; 
     602                        break; 
     603                case MVChatUserOfflineStatus: 
     604                case MVChatUserDetachedStatus: 
     605                        [self _removeUser:user]; 
     606                default: break; 
     607        } 
     608 
     609        [[NSNotificationCenter defaultCenter] postNotificationName:JVBuddyUserStatusChangedNotification object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", nil]]; 
    576610} 
    577611 
     
    600634        MVChatUser *user = [[notification userInfo] objectForKey:@"user"]; 
    601635 
    602         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _buddyOnline: ) name:MVChatConnectionWatchedUserOnlineNotification object:user]; 
    603         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _buddyOffline: ) name:MVChatConnectionWatchedUserOfflineNotification object:user]; 
     636        if( [user status] == MVChatUserAvailableStatus || [user status] == MVChatUserAwayStatus ) 
     637                [self _addUser:user]; 
     638 
    604639        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _buddyIdleUpdate: ) name:MVChatUserIdleTimeUpdatedNotification object:user]; 
    605640        [[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]; 
    606650} 
    607651@end