Changeset 3084

Show
Ignore:
Timestamp:
12/26/05 19:29:26 (3 years ago)
Author:
timothy
Message:
  • Redid the IRC tokenizer to remove the need for NSString initWithBytes to do a strlen. This also cleans up the code a little and removed the mutation of the data AsyncSocket? hands us. I'm l33t. :}
  • Parsing of CTCP requests and replies. Nothing is done with these yet except an NSLog. (Applied the new non-mutation parsing logic here also.)
Files:

Legend:

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

    r3081 r3084  
    2929- (void) _readNextMessageFromServer; 
    3030 
     31- (void) _handleCTCP:(NSMutableData *) data asRequest:(BOOL) request fromSender:(MVChatUser *) sender forRoom:(MVChatRoom *) room; 
     32         
    3133+ (NSData *) _flattenedIRCDataForMessage:(NSAttributedString *) message withEncoding:(NSStringEncoding) enc andChatFormat:(MVChatMessageFormat) format; 
    3234- (void) _sendMessage:(NSAttributedString *) message withEncoding:(NSStringEncoding) encoding toTarget:(NSString *) target asAction:(BOOL) action; 
  • branches/cocoa-networking/Chat Core/MVIRCChatConnection.m

    r3082 r3084  
    979979        } 
    980980 
     981        // IRC messages are always lines of characters terminated with a CR-LF 
     982        // (Carriage Return - Line Feed) pair, and these messages SHALL NOT 
     983        // exceed 512 characters in length, counting all characters including 
     984        // the trailing CR-LF. Thus, there are 510 characters maximum allowed 
     985        // for the command and its parameters. 
     986 
     987        if( [data length] > 510 ) [data setLength:510]; 
    981988        [data appendBytes:"\x0D\x0A" length:2]; 
    982989 
     
    11501157- (void) socket:(AsyncSocket *) sock didReadData:(NSData *) data withTag:(long) tag { 
    11511158        NSString *rawString = [[NSString allocWithZone:nil] initWithData:data encoding:[self encoding]]; 
    1152         char *line = (char *)[(NSMutableData *)data mutableBytes]; 
     1159        const char *line = (const char *)[data bytes]; 
    11531160        unsigned int len = [data length]; 
    1154  
    1155         char *sender = NULL; 
    1156         char *user = NULL; 
    1157         char *host = NULL; 
    1158         char *command = NULL; 
    1159         char *currentParameter = NULL; 
     1161        const char *end = line + len - 2; // minus the line endings 
     1162 
     1163        const char *sender = NULL; 
     1164        unsigned senderLength = 0; 
     1165        const char *user = NULL; 
     1166        unsigned userLength = 0; 
     1167        const char *host = NULL; 
     1168        unsigned hostLength = 0; 
     1169        const char *command = NULL; 
     1170        unsigned commandLength = 0; 
    11601171 
    11611172        NSMutableArray *parameters = [[NSMutableArray allocWithZone:nil] initWithCapacity:15]; 
     
    11661177                goto end; // bad message 
    11671178 
    1168 #define checkAndMarkIfDone() if( *line == '\r' || *line == '\f' || *line == '\0' ) done = YES 
    1169 #define consumeWhitespace() while( *line == ' ' && ! done ) line++ 
    1170 #define notEndOfLine() *line != '\r' && *line != '\f' && *line != '\0' && ! done 
     1179#define checkAndMarkIfDone() if( line == end ) done = YES 
     1180#define consumeWhitespace() while( *line == ' ' && line != end && ! done ) line++ 
     1181#define notEndOfLine() line != end && ! done 
    11711182 
    11721183        BOOL done = NO; 
     
    11761187                        sender = ++line; 
    11771188                        while( notEndOfLine() && *line != ' ' && *line != '!' && *line != '@' ) line++; 
     1189                        senderLength = (line - sender); 
    11781190                        checkAndMarkIfDone(); 
    11791191 
    1180                         if( *line == '!' ) { 
    1181                                 *line++ = '\0'; 
    1182                                 user = line; 
     1192                        if( ! done && *line == '!' ) { 
     1193                                user = ++line; 
    11831194                                while( notEndOfLine() && *line != ' ' && *line != '@' ) line++; 
     1195                                userLength = (line - host); 
    11841196                                checkAndMarkIfDone(); 
    1185                                 if( *line != '@' ) *line = '\0'; 
    11861197                        } 
    11871198 
    1188                         if( *line == '@' ) { 
    1189                                 *line++ = '\0'; 
    1190                                 host = line; 
     1199                        if( ! done && *line == '@' ) { 
     1200                                host = ++line; 
    11911201                                while( notEndOfLine() && *line != ' ' ) line++; 
     1202                                hostLength = (line - host); 
    11921203                                checkAndMarkIfDone(); 
    1193                                 *line = '\0'; 
    11941204                        } 
    11951205 
    1196                         *line++ = '\0'
     1206                        if( ! done ) line++
    11971207                        consumeWhitespace(); 
    11981208                } 
     
    12041214                        command = line; 
    12051215                        while( notEndOfLine() && *line != ' ' ) line++; 
    1206                         *line++ = '\0'; 
     1216                        commandLength = (line - command); 
     1217                        checkAndMarkIfDone(); 
     1218 
     1219                        if( ! done ) line++; 
    12071220                        consumeWhitespace(); 
    12081221                } 
    12091222 
    1210                 id param = nil; 
    12111223                while( notEndOfLine() ) { 
    12121224                        // params: [ ':' <trailing data> | <letter> { <letter> } ] [ ' ' { ' ' } ] [ <params> ] 
    1213                         currentParameter = NULL; 
    1214                         param = nil; 
     1225                        const char *currentParameter = NULL; 
     1226                        id param = nil; 
    12151227                        if( *line == ':' ) { 
    12161228                                currentParameter = ++line; 
    1217                                 while( notEndOfLine() ) line++; 
    1218                                 *line = '\0'; 
     1229                                param = [[NSMutableData allocWithZone:nil] initWithBytes:currentParameter length:(end - currentParameter)]; 
    12191230                                done = YES; 
    1220                                 param = [[NSData allocWithZone:nil] initWithBytes:currentParameter length:(line - currentParameter)]; 
    12211231                        } else { 
    12221232                                currentParameter = line; 
    12231233                                while( notEndOfLine() && *line != ' ' ) line++; 
     1234                                param = [[NSString allocWithZone:nil] initWithBytes:currentParameter length:(line - currentParameter) encoding:[self encoding]]; 
    12241235                                checkAndMarkIfDone(); 
    1225                                 *line++ = '\0'; 
    1226                                 param = [[NSString allocWithZone:nil] initWithBytes:currentParameter encoding:[self encoding]]; 
     1236                                if( ! done ) line++; 
    12271237                        } 
    12281238 
     
    12391249 
    12401250end: 
    1241         if( command ) { 
    1242                 NSString *commandString = [[NSString allocWithZone:nil] initWithBytes:command encoding:[self encoding]]; 
     1251        if( command && commandLength ) { 
     1252                NSString *commandString = [[NSString allocWithZone:nil] initWithBytes:command length:commandLength encoding:[self encoding]]; 
    12431253                NSString *selectorString = [[NSString allocWithZone:nil] initWithFormat:@"_handle%@WithParameters:fromSender:", [commandString capitalizedString]]; 
    12441254                SEL selector = NSSelectorFromString( selectorString ); 
     
    12481258                if( [self respondsToSelector:selector] ) { 
    12491259                        NSString *senderString = nil; 
    1250                         if( sender ) senderString = [[NSString allocWithZone:nil] initWithBytes:sender encoding:[self encoding]]; 
     1260                        if( sender ) senderString = [[NSString allocWithZone:nil] initWithBytes:sender length:senderLength encoding:[self encoding]]; 
    12511261 
    12521262                        MVChatUser *chatUser = nil; 
    1253                         if( user ) { 
     1263                        if( user && userLength ) { 
    12541264                                chatUser = [self chatUserWithUniqueIdentifier:senderString]; 
    1255                                 if( ! [chatUser address] && host ) [chatUser _setAddress:[self stringWithEncodedBytes:host]]; 
    1256                                 if( ! [chatUser username] ) [chatUser _setUsername:[self stringWithEncodedBytes:user]]; 
     1265                                if( ! [chatUser address] && host && hostLength ) { 
     1266                                        NSString *hostString = [[NSString allocWithZone:nil] initWithBytes:host length:hostLength encoding:[self encoding]]; 
     1267                                        [chatUser _setAddress:hostString]; 
     1268                                        [hostString release]; 
     1269                                } 
     1270 
     1271                                if( ! [chatUser username] ) { 
     1272                                        NSString *userString = [[NSString allocWithZone:nil] initWithBytes:user length:userLength encoding:[self encoding]]; 
     1273                                        [chatUser _setUsername:userString]; 
     1274                                        [userString release]; 
     1275                                } 
    12571276                        } 
    12581277 
     
    14421461                } 
    14431462 
    1444                 NSData *msgData = [parameters objectAtIndex:1]; 
     1463                NSMutableData *msgData = [parameters objectAtIndex:1]; 
     1464                const char *bytes = (const char *)[msgData bytes]; 
     1465                BOOL ctcp = ( *bytes == '\001' && [msgData length] > 2 ); 
     1466 
     1467                if( [sender status] != MVChatUserAwayStatus ) [sender _setStatus:MVChatUserAvailableStatus]; 
     1468                [sender _setIdleTime:0.]; 
     1469 
    14451470                if( [[self chatRoomNamePrefixes] characterIsMember:[targetName characterAtIndex:0]] ) { 
    14461471                        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]]; 
     1472                        if( ctcp ) [self _handleCTCP:msgData asRequest:YES fromSender:sender forRoom:room]; 
     1473                        else [[NSNotificationCenter defaultCenter] postNotificationName:MVChatRoomGotMessageNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", msgData, @"message", [NSString locallyUniqueString], @"identifier", nil]]; 
    14501474                } 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]]; 
     1475                        if( ctcp ) [self _handleCTCP:msgData asRequest:YES fromSender:sender forRoom:nil]; 
     1476                        else [[NSNotificationCenter defaultCenter] postNotificationName:MVChatConnectionGotPrivateMessageNotification object:sender userInfo:[NSDictionary dictionaryWithObjectsAndKeys:msgData, @"message", [NSString locallyUniqueString], @"identifier", nil]]; 
    14541477                } 
    14551478        } 
     
    14661489                } 
    14671490 
    1468                 NSData *msgData = [parameters objectAtIndex:1]; 
     1491                NSMutableData *msgData = [parameters objectAtIndex:1]; 
     1492                const char *bytes = (const char *)[msgData bytes]; 
     1493                BOOL ctcp = ( *bytes == '\001' && [msgData length] > 2 ); 
     1494 
    14691495                if( [[self chatRoomNamePrefixes] characterIsMember:[targetName characterAtIndex:0]] ) { 
    14701496                        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]]; 
     1497                        if( ctcp ) [self _handleCTCP:msgData asRequest:NO fromSender:sender forRoom:room]; 
     1498                        else [[NSNotificationCenter defaultCenter] postNotificationName:MVChatRoomGotMessageNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"notice", nil]]; 
    14731499                } 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]; 
     1500                        if( ctcp ) [self _handleCTCP:msgData asRequest:NO fromSender:sender forRoom:nil]; 
     1501                        else { 
     1502                                [[NSNotificationCenter defaultCenter] postNotificationName:MVChatConnectionGotPrivateMessageNotification object:sender userInfo:[NSDictionary dictionaryWithObjectsAndKeys:msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"notice", nil]]; 
     1503                                if( [[sender nickname] isEqualToString:@"NickServ"] ) { 
     1504                                        NSString *msg = [[NSString allocWithZone:nil] initWithData:msgData encoding:[self encoding]]; 
     1505                                        if( [msg rangeOfString:@"NickServ"].location != NSNotFound && [msg rangeOfString:@"IDENTIFY"].location != NSNotFound ) { 
     1506                                                if( ! [self nicknamePassword] ) { 
     1507                                                        [[NSNotificationCenter defaultCenter] postNotificationName:MVChatConnectionNeedNicknamePasswordNotification object:self userInfo:nil]; 
     1508                                                } else [self sendRawMessageWithFormat:@"PRIVMSG %@ :IDENTIFY %@", [self nickname], [self nicknamePassword]]; 
     1509                                        } else if( [msg rangeOfString:@"Password accepted"].location != NSNotFound ) { 
     1510                                                [[self localUser] _setIdentified:YES]; 
     1511                                        } else if( [msg rangeOfString:@"authentication required"].location != NSNotFound ) { 
     1512                                                [[self localUser] _setIdentified:NO]; 
     1513                                        } 
     1514                                        [msg release]; 
    14861515                                } 
    1487                                 [msg release]; 
    14881516                        } 
    14891517                } 
    14901518        } 
     1519} 
     1520 
     1521- (void) _handleCTCP:(NSMutableData *) data asRequest:(BOOL) request fromSender:(MVChatUser *) sender forRoom:(MVChatRoom *) room { 
     1522        NSMutableArray *parameters = [[NSMutableArray allocWithZone:nil] initWithCapacity:15]; 
     1523        const char *line = (const char *)[data bytes] + 1; // skip the \001 char 
     1524        const char *end = line + [data length] - 2; // minus the first and last \001 char 
     1525        BOOL done = NO; 
     1526 
     1527        while( line != end && ! done ) { 
     1528                // params: [ ':' <trailing data> | <letter> { <letter> } ] [ ' ' { ' ' } ] [ <params> ] 
     1529                const char *currentParameter = NULL; 
     1530                id param = nil; 
     1531                if( *line == ':' ) { 
     1532                        currentParameter = ++line; 
     1533                        param = [[NSMutableData allocWithZone:nil] initWithBytes:currentParameter length:(end - currentParameter)]; 
     1534                        done = YES; 
     1535                } else { 
     1536                        currentParameter = line; 
     1537                        while( line != end && *line != ' ' ) line++; 
     1538                        param = [[NSString allocWithZone:nil] initWithBytes:currentParameter length:(line - currentParameter) encoding:[self encoding]]; 
     1539                        if( line == end ) done = YES; 
     1540                        else line++; 
     1541                } 
     1542 
     1543                if( param ) [parameters addObject:param]; 
     1544                [param release]; 
     1545 
     1546                while( *line == ' ' && line != end && ! done ) line++; 
     1547        } 
     1548 
     1549        NSLog(@"ctcp %@ %d %@", sender, request, [parameters description] ); 
    14911550} 
    14921551