Changeset 3082

Show
Ignore:
Timestamp:
12/25/05 21:49:58 (3 years ago)
Author:
timothy
Message:
  • PRIVMSG support, along with user JOIN, QUIT and PART.
  • Optimized joined room lookup by name.
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/cocoa-networking/Chat Core/MVChatConnection.h

    r3080 r3082  
    8888 
    8989        NSString *_npassword; 
    90         NSMutableSet *_joinedRooms; 
     90        NSMutableDictionary *_joinedRooms; 
    9191        MVChatUser *_localUser; 
    9292        NSMutableDictionary *_roomsCache; 
  • branches/cocoa-networking/Chat Core/MVChatConnection.m

    r3080 r3082  
    9090                _proxy = MVChatConnectionNoProxy; 
    9191                _roomsCache = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:500]; 
    92                 _persistentInformation = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:2]; 
    93                 _joinedRooms = [[NSMutableSet allocWithZone:nil] initWithCapacity:5]; 
     92                _persistentInformation = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:5]; 
     93                _joinedRooms = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:10]; 
    9494                _localUser = nil; 
    9595 
     
    576576        NSSet *ret = nil; 
    577577        @synchronized( _joinedRooms ) { 
    578                 ret = [NSSet setWithSet:_joinedRooms]; 
     578                ret = [NSSet setWithArray:[_joinedRooms allValues]]; 
    579579        } return ret; 
    580580} 
     
    582582- (MVChatRoom *) joinedChatRoomWithName:(NSString *) name { 
    583583        @synchronized( _joinedRooms ) { 
    584                 NSEnumerator *enumerator = [_joinedRooms objectEnumerator]; 
    585                 MVChatRoom *room = nil; 
    586                 while( ( room = [enumerator nextObject] ) ) 
    587                         if( [name caseInsensitiveCompare:[room name]] == NSOrderedSame ) 
    588                                 return [[room retain] autorelease]; 
     584                return [_joinedRooms objectForKey:[name lowercaseString]]; 
    589585        } 
    590586 
     
    829825- (void) _addJoinedRoom:(MVChatRoom *) room { 
    830826        @synchronized( _joinedRooms ) { 
    831                 [_joinedRooms addObject:room]; 
     827                [_joinedRooms setObject:room forKey:[[room name] lowercaseString]]; 
    832828        } 
    833829} 
     
    835831- (void) _removeJoinedRoom:(MVChatRoom *) room { 
    836832        @synchronized( _joinedRooms ) { 
    837                 [_joinedRooms removeObject:room]; 
     833                [_joinedRooms removeObjectForKey:[[room name] lowercaseString]]; 
    838834        } 
    839835} 
  • branches/cocoa-networking/Chat Core/MVIRCChatConnection.m

    r3081 r3082  
    178178#pragma mark - 
    179179 
    180 static void MVChatJoinedRoom( CHANNEL_REC *channel ) { 
    181         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:channel -> server]; 
    182         if( ! self ) return; 
    183  
    184         MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:channel -> name]]; 
    185         [room _setDateJoined:[NSDate date]]; 
    186         [room _setDateParted:nil]; 
    187         [room _clearMemberUsers]; 
    188         [room _clearBannedUsers]; 
    189  
    190         GSList *nicks = nicklist_getnicks( channel ); 
    191         GSList *nickItem = NULL; 
    192  
    193         for( nickItem = nicks; nickItem != NULL; nickItem = g_slist_next( nickItem ) ) { 
    194                 NICK_REC *nick = nickItem -> data; 
    195                 MVChatUser *member = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick -> nick]]; 
    196  
    197                 [room _addMemberUser:member]; 
    198  
    199                 if( nick -> op ) [room _setMode:MVChatRoomMemberOperatorMode forMemberUser:member]; 
    200                 if( nick -> halfop ) [room _setMode:MVChatRoomMemberHalfOperatorMode forMemberUser:member]; 
    201                 if( nick -> voice ) [room _setMode:MVChatRoomMemberVoicedMode forMemberUser:member]; 
    202         } 
    203  
    204         NSData *topic = ( channel -> topic ? [[NSData allocWithZone:nil] initWithBytes:channel -> topic length:strlen( channel -> topic )] : nil ); 
    205         NSString *author = ( channel -> topic_by ? [self stringWithEncodedBytes:channel -> topic_by] : nil ); 
    206         MVChatUser *authorUser = ( author ? [self chatUserWithUniqueIdentifier:author] : nil ); 
    207         NSDate *time = ( channel -> topic_time ? [NSDate dateWithTimeIntervalSince1970:channel -> topic_time] : nil ); 
    208  
    209         [room _setTopic:topic byAuthor:authorUser withDate:time]; 
    210         [topic release]; 
    211  
    212         NSNotification *note = [NSNotification notificationWithName:MVChatRoomJoinedNotification object:room userInfo:nil]; 
    213         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    214 } 
    215  
    216 static void MVChatJoinedWhoList( CHANNEL_REC *channel ) { 
    217         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:channel -> server]; 
    218         if( ! self ) return; 
    219  
    220         GSList *nicks = nicklist_getnicks( channel ); 
    221         GSList *nickItem = NULL; 
    222  
    223         for( nickItem = nicks; nickItem != NULL; nickItem = g_slist_next( nickItem ) ) { 
    224                 NICK_REC *nick = nickItem -> data; 
    225                 MVChatUser *member = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick -> nick]]; 
    226  
    227                 if( nick -> realname ) [member _setRealName:[self stringWithEncodedBytes:nick -> realname]]; 
    228                 [member _setServerOperator:nick -> serverop]; 
    229  
    230                 if( nick -> host ) { 
    231                         NSString *hostmask = [self stringWithEncodedBytes:nick -> host]; 
    232                         NSArray *parts = [hostmask componentsSeparatedByString:@"@"]; 
    233                         if( [parts count] == 2 ) { 
    234                                 [member _setUsername:[parts objectAtIndex:0]]; 
    235                                 [member _setAddress:[parts objectAtIndex:1]]; 
    236                         } 
    237                 } 
    238         } 
    239  
    240         MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:channel -> name]]; 
    241         if( ! room ) return; 
    242  
    243         NSNotification *note = [NSNotification notificationWithName:MVChatRoomMemberUsersSyncedNotification object:room userInfo:nil]; 
    244         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    245 } 
    246  
    247 static void MVChatLeftRoom( CHANNEL_REC *channel ) { 
    248         if( channel -> kicked || channel -> server -> disconnected ) return; 
    249  
    250         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:channel -> server]; 
    251         if( ! self ) return; 
    252  
    253         MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:channel -> name]]; 
    254         [room _setDateParted:[NSDate date]]; 
    255  
    256         NSNotification *note = [NSNotification notificationWithName:MVChatRoomPartedNotification object:room userInfo:nil]; 
    257         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    258 } 
    259  
    260 static void MVChatRoomTopicChanged( IRC_SERVER_REC *server, const char *data, const char *nick, const char *address ) { 
    261         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; 
    262         if( ! self || ! data ) return; 
    263  
    264         char *channel = NULL; 
    265         char *topic = NULL; 
    266         char *params = event_get_params( data, 2, &channel, &topic ); 
    267  
    268         if( ! topic || ! channel ) return; 
    269  
    270         NSData *msgData = [[NSData allocWithZone:nil] initWithBytes:topic length:strlen( topic )]; 
    271  
    272         NSString *author = ( nick ? [self stringWithEncodedBytes:nick] : nil ); 
    273         MVChatUser *authorUser = ( author ? [self chatUserWithUniqueIdentifier:author] : nil ); 
    274  
    275         MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:channel]]; 
    276         [room _setTopic:msgData byAuthor:authorUser withDate:[NSDate date]]; 
    277  
    278         [msgData release]; 
    279         g_free( params ); 
    280 } 
    281  
    282 #pragma mark - 
    283  
    284 static void MVChatUserJoinedRoom( IRC_SERVER_REC *server, const char *data, const char *nick, const char *address ) { 
    285         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; 
    286         if( ! self ) return; 
    287  
    288         char *channel = NULL; 
    289         char *params = event_get_params( data, 1, &channel ); 
    290  
    291         if( [[self nickname] isEqualToString:[self stringWithEncodedBytes:nick]] ) { 
    292                 // this is the local user, create the room object now as early as possible 
    293                 MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:channel]]; 
    294                 if( ! room ) { 
    295                         room = [[MVIRCChatRoom allocWithZone:nil] initWithName:[self stringWithEncodedBytes:channel] andConnection:self]; 
    296                         [self _addJoinedRoom:room]; 
    297                         [room release]; 
    298                 } 
    299  
    300                 goto finish; // the rest of this function doesn't apply since it is just the local user 
    301         } 
    302  
    303         CHANNEL_REC *chan = channel_find( (SERVER_REC *) server, channel ); 
    304         NICK_REC *nickname = nicklist_find( chan, nick ); 
    305  
    306         if( ! nickname ) goto finish; 
    307  
    308         MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:channel]]; 
    309         MVChatUser *member = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    310         if( [member status] != MVChatUserAwayStatus ) [member _setStatus:MVChatUserAvailableStatus]; 
    311  
    312         [room _addMemberUser:member]; 
    313  
    314         if( nickname -> op ) [room _setMode:MVChatRoomMemberOperatorMode forMemberUser:member]; 
    315         if( nickname -> halfop ) [room _setMode:MVChatRoomMemberHalfOperatorMode forMemberUser:member]; 
    316         if( nickname -> voice ) [room _setMode:MVChatRoomMemberVoicedMode forMemberUser:member]; 
    317  
    318         if( nickname -> realname ) [member _setRealName:[self stringWithEncodedBytes:nickname -> realname]]; 
    319         [member _setServerOperator:nickname -> serverop]; 
    320  
    321         if( nickname -> host ) { 
    322                 NSString *hostmask = [self stringWithEncodedBytes:nickname -> host]; 
    323                 NSArray *parts = [hostmask componentsSeparatedByString:@"@"]; 
    324                 if( [parts count] == 2 ) { 
    325                         [member _setUsername:[parts objectAtIndex:0]]; 
    326                         [member _setAddress:[parts objectAtIndex:1]]; 
    327                 } 
    328         } 
    329  
    330         NSNotification *note = [NSNotification notificationWithName:MVChatRoomUserJoinedNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:member, @"user", nil]]; 
    331         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    332  
    333 finish: 
    334         g_free( params ); 
    335 } 
    336  
    337 static void MVChatUserLeftRoom( IRC_SERVER_REC *server, const char *data, const char *nick, const char *address ) { 
    338         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; 
    339         if( ! self ) return; 
    340  
    341         if( [[self nickname] isEqualToString:[self stringWithEncodedBytes:nick]] ) return; 
    342  
    343         char *channel = NULL; 
    344         char *reason = NULL; 
    345         char *params = event_get_params( data, 2 | PARAM_FLAG_GETREST, &channel, &reason ); 
    346  
    347         MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:channel]]; 
    348         MVChatUser *member = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    349  
    350         [room _removeMemberUser:member]; 
    351  
    352         NSData *reasonData = [[NSData allocWithZone:nil] initWithBytes:reason length:strlen( reason )]; 
    353         NSNotification *note = [NSNotification notificationWithName:MVChatRoomUserPartedNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:member, @"user", reasonData, @"reason", nil]]; 
    354         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    355  
    356         [reasonData release]; 
    357         g_free( params ); 
    358 } 
    359  
    360 static void MVChatUserQuit( IRC_SERVER_REC *server, const char *data, const char *nick, const char *address ) { 
    361         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; 
    362         if( ! self ) return; 
    363  
    364         if( [[self nickname] isEqualToString:[self stringWithEncodedBytes:nick]] ) return; 
    365  
    366         if( *data == ':' ) data++; 
    367  
    368         MVChatUser *member = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    369         NSData *reasonData = [[NSData allocWithZone:nil] initWithBytes:data length:strlen( data )]; 
    370         NSEnumerator *enumerator = [[self joinedChatRooms] objectEnumerator]; 
    371         MVChatRoom *room = nil; 
    372  
    373         [member _setDateDisconnected:[NSDate date]]; 
    374         [member _setStatus:MVChatUserOfflineStatus]; 
    375  
    376         NSDictionary *info = [[NSDictionary allocWithZone:nil] initWithObjectsAndKeys:member, @"user", reasonData, @"reason", nil]; 
    377         while( ( room = [enumerator nextObject] ) ) { 
    378                 if( ! [room isJoined] || ! [room hasUser:member] ) continue; 
    379                 [room _removeMemberUser:member]; 
    380                 NSNotification *note = [NSNotification notificationWithName:MVChatRoomUserPartedNotification object:room userInfo:info]; 
    381                 [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    382         } 
    383  
    384         [info release]; 
    385         [reasonData release]; 
    386 } 
    387  
    388180static void MVChatUserKicked( IRC_SERVER_REC *server, const char *data, const char *by, const char *address ) { 
    389181        MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; 
     
    457249        NSNotification *note = [NSNotification notificationWithName:MVChatConnectionSelfAwayStatusChangedNotification object:self userInfo:nil]; 
    458250        [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    459 } 
    460  
    461 #pragma mark - 
    462  
    463 static void MVChatGetMessage( IRC_SERVER_REC *server, const char *data, const char *nick, const char *address ) { 
    464         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; 
    465         if( ! self ) return; 
    466         if( ! nick ) return; 
    467  
    468         char *target = NULL, *message = NULL; 
    469         char *params = event_get_params( data, 2 | PARAM_FLAG_GETREST, &target, &message ); 
    470         if( ! address ) address = ""; 
    471  
    472         if( *target == '@' && ischannel( target[1] ) ) target++; 
    473  
    474         NSData *msgData = [[NSData allocWithZone:nil] initWithBytes:message length:strlen( message )]; 
    475         NSNotification *note = nil; 
    476  
    477         if( ischannel( *target ) ) { 
    478                 MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:target]]; 
    479                 MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    480                 if( [user status] != MVChatUserAwayStatus ) [user _setStatus:MVChatUserAvailableStatus]; 
    481                 [user _setIdleTime:0.]; 
    482                 note = [NSNotification notificationWithName:MVChatRoomGotMessageNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", msgData, @"message", [NSString locallyUniqueString], @"identifier", nil]]; 
    483         } else { 
    484                 MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    485                 if( [user status] != MVChatUserAwayStatus ) [user _setStatus:MVChatUserAvailableStatus]; 
    486                 [user _setIdleTime:0.]; 
    487                 note = [NSNotification notificationWithName:MVChatConnectionGotPrivateMessageNotification object:user userInfo:[NSDictionary dictionaryWithObjectsAndKeys:msgData, @"message", [NSString locallyUniqueString], @"identifier", nil]]; 
    488         } 
    489  
    490         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    491  
    492         [msgData release]; 
    493         g_free( params ); 
    494 } 
    495  
    496 static void MVChatGetAutoMessage( IRC_SERVER_REC *server, const char *data, const char *nick, const char *address ) { 
    497         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; 
    498         if( ! self ) return; 
    499         if( ! nick ) return; 
    500  
    501         char *target = NULL, *message = NULL; 
    502         char *params = event_get_params( data, 2 | PARAM_FLAG_GETREST, &target, &message ); 
    503         if( ! address ) address = ""; 
    504  
    505         if( *target == '@' && ischannel( target[1] ) ) target++; 
    506  
    507         NSNotification *note = nil; 
    508         NSData *msgData = [[NSData allocWithZone:nil] initWithBytes:message length:strlen( message )]; 
    509  
    510         if( ischannel( *target ) ) { 
    511                 MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:target]]; 
    512                 MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    513                 if( [user status] != MVChatUserAwayStatus ) [user _setStatus:MVChatUserAvailableStatus]; 
    514                 note = [NSNotification notificationWithName:MVChatRoomGotMessageNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"notice", nil]]; 
    515         } else { 
    516                 MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    517                 if( [user status] != MVChatUserAwayStatus ) [user _setStatus:MVChatUserAvailableStatus]; 
    518                 note = [NSNotification notificationWithName:MVChatConnectionGotPrivateMessageNotification object:user userInfo:[NSDictionary dictionaryWithObjectsAndKeys:msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"notice", nil]]; 
    519                 if( ! strncasecmp( nick, "NickServ", 8 ) && message ) { 
    520                         if( strstr( message, nick ) && strstr( message, "IDENTIFY" ) ) { 
    521                                 if( ! [self nicknamePassword] ) { 
    522                                         NSNotification *note = [NSNotification notificationWithName:MVChatConnectionNeedNicknamePasswordNotification object:self userInfo:nil]; 
    523                                         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    524                                 } else irc_send_cmdv( server, "PRIVMSG %s :IDENTIFY %s", nick, [self encodedBytesWithString:[self nicknamePassword]] ); 
    525                         } else if( strstr( message, "Password accepted" ) ) { 
    526                                 [[self localUser] _setIdentified:YES]; 
    527                         } else if( strstr( message, "authentication required" ) ) { 
    528                                 [[self localUser] _setIdentified:NO]; 
    529                         } 
    530                 } 
    531         } 
    532  
    533         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    534  
    535         [msgData release]; 
    536         g_free( params ); 
    537 } 
    538  
    539 static void MVChatGetActionMessage( IRC_SERVER_REC *server, const char *data, const char *nick, const char *address, const char *target ) { 
    540         MVIRCChatConnection *self = [MVIRCChatConnection _connectionForServer:(SERVER_REC *)server]; 
    541         if( ! self ) return; 
    542         if( ! nick ) return; 
    543         if( ! address ) address = ""; 
    544  
    545         NSData *msgData = [[NSData allocWithZone:nil] initWithBytes:data length:strlen( data )]; 
    546         NSNotification *note = nil; 
    547  
    548         if( ischannel( *target ) ) { 
    549                 MVChatRoom *room = [self joinedChatRoomWithName:[self stringWithEncodedBytes:target]]; 
    550                 MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    551                 if( [user status] != MVChatUserAwayStatus ) [user _setStatus:MVChatUserAvailableStatus]; 
    552                 [user _setIdleTime:0.]; 
    553                 note = [NSNotification notificationWithName:MVChatRoomGotMessageNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:user, @"user", msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"action", nil]]; 
    554         } else { 
    555                 MVChatUser *user = [self chatUserWithUniqueIdentifier:[self stringWithEncodedBytes:nick]]; 
    556                 if( [user status] != MVChatUserAwayStatus ) [user _setStatus:MVChatUserAvailableStatus]; 
    557                 [user _setIdleTime:0.]; 
    558                 note = [NSNotification notificationWithName:MVChatConnectionGotPrivateMessageNotification object:user userInfo:[NSDictionary dictionaryWithObjectsAndKeys:msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"action", nil]]; 
    559         } 
    560  
    561         [[NSNotificationCenter defaultCenter] postNotificationOnMainThread:note]; 
    562         [msgData release]; 
    563251} 
    564252 
     
    13371025 
    13381026- (NSCharacterSet *) chatRoomNamePrefixes { 
    1339         return [NSCharacterSet characterSetWithCharactersInString:@"#&+!"]; 
     1027        static NSCharacterSet *prefixes = nil; 
     1028        if( ! prefixes ) prefixes = [[NSCharacterSet characterSetWithCharactersInString:@"#&+!"] retain]; 
     1029        return prefixes; 
    13401030} 
    13411031 
     
    17421432 
    17431433@implementation MVIRCChatConnection (MVIRCChatConnectionProtocolHandlers) 
    1744 - (void) _handleJoinWithParameters:(NSArray *) parameters fromSender:(id) sender { 
     1434- (void) _handlePrivmsgWithParameters:(NSArray *) parameters fromSender:(MVChatUser *) sender { 
     1435        if( [parameters count] == 2 ) { 
     1436                NSString *targetName = [parameters objectAtIndex:0]; 
     1437                if( ! [targetName length] ) return; 
     1438 
     1439                if( [targetName characterAtIndex:0] == '@' ) { 
     1440                        targetName = [targetName substringFromIndex:1]; // a message to only room operators 
     1441                        if( ! [targetName length] ) return; 
     1442                } 
     1443 
     1444                NSData *msgData = [parameters objectAtIndex:1]; 
     1445                if( [[self chatRoomNamePrefixes] characterIsMember:[targetName characterAtIndex:0]] ) { 
     1446                        MVChatRoom *room = [self joinedChatRoomWithName:targetName]; 
     1447                        if( [sender status] != MVChatUserAwayStatus ) [sender _setStatus:MVChatUserAvailableStatus]; 
     1448                        [sender _setIdleTime:0.]; 
     1449                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatRoomGotMessageNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", msgData, @"message", [NSString locallyUniqueString], @"identifier", nil]]; 
     1450                } else { 
     1451                        if( [sender status] != MVChatUserAwayStatus ) [sender _setStatus:MVChatUserAvailableStatus]; 
     1452                        [sender _setIdleTime:0.]; 
     1453                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatConnectionGotPrivateMessageNotification object:sender userInfo:[NSDictionary dictionaryWithObjectsAndKeys:msgData, @"message", [NSString locallyUniqueString], @"identifier", nil]]; 
     1454                } 
     1455        } 
     1456
     1457 
     1458- (void) _handleNoticeWithParameters:(NSArray *) parameters fromSender:(MVChatUser *) sender { 
     1459        if( [parameters count] == 2 ) { 
     1460                NSString *targetName = [parameters objectAtIndex:0]; 
     1461                if( ! [targetName length] ) return; 
     1462 
     1463                if( [targetName characterAtIndex:0] == '@' ) { 
     1464                        targetName = [targetName substringFromIndex:1]; // a message to only room operators 
     1465                        if( ! [targetName length] ) return; 
     1466                } 
     1467 
     1468                NSData *msgData = [parameters objectAtIndex:1]; 
     1469                if( [[self chatRoomNamePrefixes] characterIsMember:[targetName characterAtIndex:0]] ) { 
     1470                        MVChatRoom *room = [self joinedChatRoomWithName:targetName]; 
     1471                        if( [sender status] != MVChatUserAwayStatus ) [sender _setStatus:MVChatUserAvailableStatus]; 
     1472                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatRoomGotMessageNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"notice", nil]]; 
     1473                } else { 
     1474                        if( [sender status] != MVChatUserAwayStatus ) [sender _setStatus:MVChatUserAvailableStatus]; 
     1475                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatConnectionGotPrivateMessageNotification object:sender userInfo:[NSDictionary dictionaryWithObjectsAndKeys:msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"notice", nil]]; 
     1476                        if( [[sender nickname] isEqualToString:@"NickServ"] ) { 
     1477                                NSString *msg = [[NSString allocWithZone:nil] initWithData:msgData encoding:[self encoding]]; 
     1478                                if( [msg rangeOfString:@"NickServ"].location != NSNotFound && [msg rangeOfString:@"IDENTIFY"].location != NSNotFound ) { 
     1479                                        if( ! [self nicknamePassword] ) { 
     1480                                                [[NSNotificationCenter defaultCenter] postNotificationName:MVChatConnectionNeedNicknamePasswordNotification object:self userInfo:nil]; 
     1481                                        } else [self sendRawMessageWithFormat:@"PRIVMSG %@ :IDENTIFY %@", [self nickname], [self nicknamePassword]]; 
     1482                                } else if( [msg rangeOfString:@"Password accepted"].location != NSNotFound ) { 
     1483                                        [[self localUser] _setIdentified:YES]; 
     1484                                } else if( [msg rangeOfString:@"authentication required"].location != NSNotFound ) { 
     1485                                        [[self localUser] _setIdentified:NO]; 
     1486                                } 
     1487                                [msg release]; 
     1488                        } 
     1489                } 
     1490        } 
     1491
     1492 
     1493- (void) _handleJoinWithParameters:(NSArray *) parameters fromSender:(MVChatUser *) sender { 
    17451494        if( [parameters count] ) { 
    17461495                NSString *name = [[NSString allocWithZone:nil] initWithData:[parameters objectAtIndex:0] encoding:[self encoding]]; 
     
    17591508                        [room _clearMemberUsers]; 
    17601509                        [room _clearBannedUsers]; 
    1761                         [name release]; 
    17621510 
    17631511                        [self sendRawMessageWithFormat:@"WHO %@", name]; 
    17641512                } else { 
    1765                         // user joined room 
     1513                        if( [sender status] != MVChatUserAwayStatus ) [sender _setStatus:MVChatUserAvailableStatus]; 
     1514                        [sender _setIdleTime:0.]; 
     1515                        [room _addMemberUser:sender]; 
     1516                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatRoomUserJoinedNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", nil]]; 
    17661517                } 
     1518 
     1519                [name release]; 
     1520        } 
     1521} 
     1522 
     1523- (void) _handlePartWithParameters:(NSArray *) parameters fromSender:(MVChatUser *) sender { 
     1524        if( [parameters count] == 2 ) { 
     1525                MVChatRoom *room = [self joinedChatRoomWithName:[parameters objectAtIndex:0]]; 
     1526                if( ! room ) return; 
     1527                if( [sender isLocalUser] ) { 
     1528                        [room _setDateParted:[NSDate date]]; 
     1529                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatRoomPartedNotification object:room]; 
     1530                } else { 
     1531                        [room _removeMemberUser:sender]; 
     1532                        NSData *reason = [parameters objectAtIndex:1]; 
     1533                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatRoomUserPartedNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", reason, @"reason", nil]]; 
     1534                } 
     1535        } 
     1536} 
     1537 
     1538- (void) _handleQuitWithParameters:(NSArray *) parameters fromSender:(MVChatUser *) sender { 
     1539        if( [sender isLocalUser] ) return; 
     1540        if( [parameters count] ) { 
     1541                [sender _setDateDisconnected:[NSDate date]]; 
     1542                [sender _setStatus:MVChatUserOfflineStatus]; 
     1543 
     1544                NSData *reason = [parameters objectAtIndex:0]; 
     1545                NSDictionary *info = [[NSDictionary allocWithZone:nil] initWithObjectsAndKeys:sender, @"user", reason, @"reason", nil]; 
     1546 
     1547                MVChatRoom *room = nil; 
     1548                NSEnumerator *enumerator = [[self joinedChatRooms] objectEnumerator]; 
     1549                while( ( room = [enumerator nextObject] ) ) { 
     1550                        if( ! [room isJoined] || ! [room hasUser:sender] ) continue; 
     1551                        [room _removeMemberUser:sender]; 
     1552                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatRoomUserPartedNotification object:room userInfo:info]; 
     1553                } 
     1554 
     1555                [info release]; 
     1556        } 
     1557} 
     1558 
     1559- (void) _handleTopicWithParameters:(NSArray *) parameters fromSender:(MVChatUser *) sender { 
     1560        if( [parameters count] == 2 ) { 
     1561                MVChatRoom *room = [self joinedChatRoomWithName:[parameters objectAtIndex:0]]; 
     1562                [room _setTopic:[parameters objectAtIndex:1] byAuthor:sender withDate:[NSDate date]]; 
    17671563        } 
    17681564} 
     
    17721568                MVChatRoom *room = [self joinedChatRoomWithName:[parameters objectAtIndex:2]]; 
    17731569                if( room && ! [room _namesSynced] ) { 
     1570                        NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:nil] init]; 
    17741571                        NSString *names = [[NSString allocWithZone:nil] initWithData:[parameters objectAtIndex:3] encoding:[self encoding]]; 
    17751572                        NSArray *members = [names componentsSeparatedByString:@" "]; 
     
    18021599 
    18031600                        [names release]; 
     1601                        [pool drain]; 
     1602                        [pool release]; 
    18041603                } 
    18051604        }