Changeset 3076

Show
Ignore:
Timestamp:
12/24/05 02:58:03 (3 years ago)
Author:
timothy
Message:
  • Fleshed out more of the methods for the connection.
  • Connecting and disconnecting work now.
  • IRC message parsing implemented for easy handling later. Currently they are just logged to the console.
  • Sending commands from the console works. Sent commands aren't echoed yet.
Files:

Legend:

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

    r3075 r3076  
    1 // 
    21//  AsyncSocket.h 
    32// 
     
    76// 
    87//  E-Mail: d-j-v@earthlink.net 
    9 // 
    108 
    119/* 
     
    2220extern NSString *const AsyncSocketErrorDomain; 
    2321 
    24 enum AsyncSocketError 
    25 
     22enum AsyncSocketError { 
    2623        AsyncSocketCFSocketError = kCFSocketError,      // From CFSocketError enum. 
    2724        AsyncSocketNoError = 0,                                         // Never used. 
     
    3027        AsyncSocketWriteTimeoutError 
    3128}; 
     29 
    3230typedef enum AsyncSocketError AsyncSocketError; 
    3331 
    34 @interface NSObject ( AsyncSocketDelegate ) 
    35  
     32@interface NSObject (AsyncSocketDelegate) 
    3633/* In the event of an error, the socket is closed. You may call "readDataWithTimeout:tag:" during this call-back to get the last bit of data off the socket. When connecting, this delegate method may be called before "socket:didAcceptNewSocket:" or "socket:didConnectToHost:". */ 
    37 -(void) socket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err; 
     34- (void) socket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err; 
    3835 
    3936/* Called when a socket disconnects with or without error. If you want to release a socket after it disconnects, do so here. It is not safe to do that during "socket:willDisconnectWithError:". */ 
    40 -(void) socketDidDisconnect:(AsyncSocket *)sock; 
     37- (void) socketDidDisconnect:(AsyncSocket *)sock; 
    4138 
    4239/* Called when a socket accepts a connection. Another socket is spawned to handle it. The new socket will have the same delegate and will call "socket:didConnectToHost:port:". */ 
    43 -(void) socket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket; 
     40- (void) socket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket; 
    4441 
    4542/* Called when a new socket is spawned to handle a connection. This method should return the run-loop of the thread on which the new socket and its delegate should operate. If omitted, [NSRunLoop currentRunLoop] is used. */ 
    46 -(NSRunLoop *) socket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket; 
     43- (NSRunLoop *) socket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket; 
    4744 
    4845/* Called when a socket is about to connect. This method should return YES to continue, or NO to abort. If aborted, will result in AsyncSocketCanceledError. */ 
    49 -(BOOL) socketWillConnect:(AsyncSocket *)sock; 
     46- (BOOL) socketWillConnect:(AsyncSocket *)sock; 
    5047 
    5148/* Called when a socket connects and is ready for reading and writing. "host" will be an IP address, not a DNS name. */ 
    52 -(void) socket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port; 
     49- (void) socket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port; 
    5350 
    5451/* Called when a socket has completed reading the requested data. Not called if there is an error. */ 
    55 -(void) socket:(AsyncSocket *)sock didReadData:(NSData*)data withTag:(long)tag; 
     52- (void) socket:(AsyncSocket *)sock didReadData:(NSData*)data withTag:(long)tag; 
    5653 
    5754/* Called when a socket has completed writing the requested data. Not called if there is an error. */ 
    58 -(void) socket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag; 
    59  
     55- (void) socket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag; 
    6056@end 
    6157 
    62 @interface AsyncSocket : NSObject 
    63 
     58@interface AsyncSocket : NSObject { 
    6459        CFSocketRef theSocket;                  // IPv4/IPv6 accept or connect socket. 
    6560        CFSocketRef theSocket6;                 // IPv6 accept socket. 
     
    7671        NSTimer *theReadTimer; 
    7772        NSData *partialReadBuffer; 
    78          
     73 
    7974        NSMutableArray *theWriteQueue; 
    8075        AsyncWritePacket *theCurrentWrite; 
     
    8479        id theDelegate; 
    8580        Byte theFlags; 
    86          
     81 
    8782        long theUserData; 
    8883} 
    89  
    9084- (id) init; 
    9185- (id) initWithDelegate:(id)delegate; 
     
    154148+ (NSData *) LFData; // 0x0A 
    155149+ (NSData *) ZeroData; // 0x00 
    156  
    157150@end 
  • branches/cocoa-networking/Chat Core/MVIRCChatConnection.h

    r3075 r3076  
    11#import "MVChatConnection.h" 
     2 
     3@class AsyncSocket; 
    24 
    35@interface MVIRCChatConnection : MVChatConnection { 
    46@private 
     7        AsyncSocket *_chatConnection; 
    58        NSMutableDictionary *_knownUsers; 
     9        NSString *_server; 
     10        NSString *_currentNickname; 
     11        NSString *_nickname; 
     12        NSString *_username; 
     13        NSString *_password; 
     14        NSString *_realName; 
     15        NSString *_proxyServer; 
    616        NSString *_proxyUsername; 
    717        NSString *_proxyPassword; 
     18        unsigned short _serverPort; 
     19        unsigned short _proxyServerPort; 
     20        BOOL _secure; 
    821} 
    922+ (NSArray *) defaultServerPorts; 
     
    1326 
    1427@interface MVChatConnection (MVIRCChatConnectionPrivate) 
     28- (void) _readNextMessageFromServer; 
     29 
    1530+ (const char *) _flattenedIRCStringForMessage:(NSAttributedString *) message withEncoding:(NSStringEncoding) enc andChatFormat:(MVChatMessageFormat) format; 
    1631- (void) _forceDisconnect; 
  • branches/cocoa-networking/Chat Core/MVIRCChatConnection.m

    r3075 r3076  
    44#import "MVIRCFileTransfer.h" 
    55 
     6#import "AsyncSocket.h" 
    67#import "MVChatPluginManager.h" 
    78#import "NSAttributedStringAdditions.h" 
     
    10901091                tooLate = YES; 
    10911092        } 
    1092 } 
     1093} */ 
    10931094 
    10941095+ (NSArray *) defaultServerPorts { 
     
    11021103                _proxyUsername = nil; 
    11031104                _proxyPassword = nil; 
    1104                 _chatConnection = NULL; 
    1105                 _chatConnectionSettings = NULL; 
     1105                _chatConnection = [[AsyncSocket allocWithZone:nil] initWithDelegate:self]; 
    11061106 
    11071107                _knownUsers = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:200]; 
    11081108 
    1109               extern unsigned int connectionCount; 
    1110               connectionCount++; 
    1111  
    1112               while( ! irssiThreadReady ) usleep( 50 ); 
    1113  
    1114               IrssiLock(); 
     1109//            extern unsigned int connectionCount; 
     1110//            connectionCount++; 
     1111 
     1112//            while( ! irssiThreadReady ) usleep( 50 ); 
     1113 
     1114/*            IrssiLock(); 
    11151115 
    11161116                CHAT_PROTOCOL_REC *proto = chat_protocol_find_id( IRC_PROTOCOL ); 
     
    11301130                [self _setIrssiConnectSettings:settings]; 
    11311131 
    1132                 IrssiUnlock(); 
     1132                IrssiUnlock(); */ 
    11331133        } 
    11341134 
     
    11481148        _proxyPassword = nil; 
    11491149 
    1150       [self _setIrssiConnection:NULL]; 
    1151       [self _setIrssiConnectSettings:NULL]; 
    1152  
    1153       extern unsigned int connectionCount; 
    1154       connectionCount--; 
     1150//    [self _setIrssiConnection:NULL]; 
     1151//    [self _setIrssiConnectSettings:NULL]; 
     1152 
     1153//    extern unsigned int connectionCount; 
     1154//    connectionCount--; 
    11551155 
    11561156        [super dealloc]; 
     
    11921192        [self _willConnect]; // call early so other code has a chance to change our info 
    11931193 
    1194         IrssiLock(); 
     1194        if( ! [_chatConnection connectToHost:[self server] onPort:[self serverPort] error:NULL] ) { 
     1195                NSLog( @"failed to connect" ); 
     1196        } 
     1197 
     1198/*      IrssiLock(); 
    11951199 
    11961200        if( ! _chatConnectionSettings ) { 
     
    12361240        _chatConnection -> rawlog = NULL; 
    12371241 
    1238         IrssiUnlock(); 
     1242        IrssiUnlock(); */ 
    12391243} 
    12401244 
     
    12421246        [self cancelPendingReconnectAttempts]; 
    12431247 
    1244         if( ! _chatConnection ) return; 
    1245         if( [self status] == MVChatConnectionConnectingStatus ) { 
    1246                 [self _forceDisconnect]; 
    1247                 return; 
    1248         } 
    1249  
    1250         if( [[reason string] length] ) { 
    1251                 const char *msg = [[self class] _flattenedIRCStringForMessage:reason withEncoding:[self encoding] andChatFormat:[self outgoingChatFormat]]; 
    1252                 [self sendRawMessage:[NSString stringWithFormat:@"QUIT :%s", msg] immediately:YES]; 
    1253         } else [self sendRawMessage:@"QUIT" immediately:YES]; 
    1254  
    1255         IrssiLock(); 
    1256  
    1257         if( _chatConnection ) { 
    1258                 _chatConnection -> connection_lost = NO; 
    1259                 _chatConnection -> no_reconnect = YES; 
    1260                 server_disconnect( _chatConnection ); 
    1261         } 
    1262  
    1263         IrssiUnlock(); 
     1248        if( [self status] == MVChatConnectionConnectedStatus ) { 
     1249                if( [[reason string] length] ) { 
     1250                        const char *msg = [[self class] _flattenedIRCStringForMessage:reason withEncoding:[self encoding] andChatFormat:[self outgoingChatFormat]]; 
     1251                        [self sendRawMessage:[NSString stringWithFormat:@"QUIT :%s", msg] immediately:YES]; 
     1252                } else [self sendRawMessage:@"QUIT" immediately:YES]; 
     1253        } 
     1254 
     1255        [_chatConnection disconnectAfterWriting]; 
    12641256} 
    12651257 
     
    12691261        NSParameterAssert( name != nil ); 
    12701262 
    1271         IrssiLock(); 
    1272  
    1273         if( _chatConnectionSettings ) { 
    1274                 g_free_not_null( _chatConnectionSettings -> realname ); 
    1275                 _chatConnectionSettings -> realname = g_strdup( [self encodedBytesWithString:name] ); 
    1276         } 
    1277  
    1278         IrssiUnlock(); 
     1263        id old = _realName; 
     1264        _realName = [name copyWithZone:nil]; 
     1265        [old release]; 
    12791266} 
    12801267 
    12811268- (NSString *) realName { 
    1282         if( ! _chatConnectionSettings ) return nil; 
    1283         return [self stringWithEncodedBytes:_chatConnectionSettings -> realname]; 
     1269        return [[_realName retain] autorelease]; 
    12841270} 
    12851271 
     
    12901276        NSParameterAssert( [nickname length] > 0 ); 
    12911277 
    1292         IrssiLock(); 
    1293  
    1294         if( _chatConnectionSettings ) { 
    1295                 g_free_not_null( _chatConnectionSettings -> nick ); 
    1296                 _chatConnectionSettings -> nick = g_strdup( [self encodedBytesWithString:nickname] ); 
    1297         } 
    1298  
    1299         IrssiUnlock(); 
     1278        id old = _nickname; 
     1279        _nickname = [nickname copyWithZone:nil]; 
     1280        [old release]; 
     1281 
     1282        if( ! _currentNickname ) 
     1283                _currentNickname = [_nickname retain]; 
    13001284 
    13011285        if( [self isConnected] && ! [nickname isEqualToString:[self nickname]] ) 
     
    13041288 
    13051289- (NSString *) nickname { 
    1306         if( _status == MVChatConnectionConnectedStatus ) { // don't call [self isConnected], need speed here 
    1307                 IrssiLock(); 
    1308                 NSString *nick = nil; 
    1309                 if( _chatConnection && _chatConnection -> nick ) 
    1310                         nick = [self stringWithEncodedBytes:_chatConnection -> nick]; 
    1311                 IrssiUnlock(); 
    1312                 if( nick ) return nick; 
    1313         } 
    1314  
    1315         if( ! _chatConnectionSettings ) return nil; 
    1316         return [self stringWithEncodedBytes:_chatConnectionSettings -> nick]; 
     1290        return [[_currentNickname retain] autorelease]; 
    13171291} 
    13181292 
    13191293- (NSString *) preferredNickname { 
    1320         if( ! _chatConnectionSettings ) return nil; 
    1321         return [self stringWithEncodedBytes:_chatConnectionSettings -> nick]; 
     1294        return [[_nickname retain] autorelease]; 
    13221295} 
    13231296 
     
    13331306 
    13341307- (void) setPassword:(NSString *) password { 
    1335         IrssiLock(); 
    1336  
    1337         if( _chatConnectionSettings ) { 
    1338                 g_free_not_null( _chatConnectionSettings -> password ); 
    1339                 if( [password length] ) _chatConnectionSettings -> password = g_strdup( [self encodedBytesWithString:password] ); 
    1340                 else _chatConnectionSettings -> password = NULL; 
    1341         } 
    1342  
    1343         IrssiUnlock(); 
     1308        id old = _password; 
     1309        _password = [password copyWithZone:nil]; 
     1310        [old release]; 
    13441311} 
    13451312 
    13461313- (NSString *) password { 
    1347         if( ! _chatConnectionSettings ) return nil; 
    1348         char *pass = _chatConnectionSettings -> password; 
    1349         if( pass ) return [self stringWithEncodedBytes:pass]; 
    1350         return nil; 
     1314        return [[_password retain] autorelease]; 
    13511315} 
    13521316 
     
    13571321        NSParameterAssert( [username length] > 0 ); 
    13581322 
    1359         IrssiLock(); 
    1360  
    1361         if( _chatConnectionSettings ) { 
    1362                 g_free_not_null( _chatConnectionSettings -> username ); 
    1363                 _chatConnectionSettings -> username = g_strdup( [self encodedBytesWithString:username] ); 
    1364         } 
    1365  
    1366         IrssiUnlock(); 
     1323        id old = _username; 
     1324        _username = [username copyWithZone:nil]; 
     1325        [old release]; 
    13671326} 
    13681327 
    13691328- (NSString *) username { 
    1370         if( ! _chatConnectionSettings ) return nil; 
    1371         return [self stringWithEncodedBytes:_chatConnectionSettings -> username]; 
     1329        return [[_username retain] autorelease]; 
    13721330} 
    13731331 
     
    13781336        NSParameterAssert( [server length] > 0 ); 
    13791337 
    1380         IrssiLock(); 
    1381  
    1382         if( _chatConnectionSettings ) { 
    1383                 g_free_not_null( _chatConnectionSettings -> address ); 
    1384                 _chatConnectionSettings -> address = g_strdup( [self encodedBytesWithString:server] ); 
    1385         } 
    1386  
    1387         IrssiUnlock(); 
     1338        id old = _server; 
     1339        _server = [server copyWithZone:nil]; 
     1340        [old release]; 
    13881341} 
    13891342 
    13901343- (NSString *) server { 
    1391         if( ! _chatConnectionSettings ) return nil; 
    1392         return [self stringWithEncodedBytes:_chatConnectionSettings -> address]; 
     1344        return [[_server retain] autorelease]; 
    13931345} 
    13941346 
     
    13961348 
    13971349- (void) setServerPort:(unsigned short) port { 
    1398         IrssiLock(); 
    1399         if( _chatConnectionSettings ) 
    1400                 _chatConnectionSettings -> port = ( port ? port : 6667 ); 
    1401         IrssiUnlock(); 
     1350        _serverPort = ( port ? port : 6667 ); 
    14021351} 
    14031352 
    14041353- (unsigned short) serverPort { 
    1405         if( ! _chatConnectionSettings ) return 0; 
    1406         return _chatConnectionSettings -> port; 
     1354        return _serverPort; 
    14071355} 
    14081356 
     
    14101358 
    14111359- (void) setSecure:(BOOL) ssl { 
    1412         IrssiLock(); 
    1413  
    1414         if( _chatConnectionSettings ) { 
    1415                 _chatConnectionSettings -> use_ssl = ssl; 
    1416                 _chatConnectionSettings -> ssl_verify = NO; 
    1417         } 
    1418  
    1419         IrssiUnlock(); 
     1360        _secure = ssl; 
    14201361} 
    14211362 
    14221363- (BOOL) isSecure { 
    1423         if( ! _chatConnectionSettings ) return NO; 
    1424         return _chatConnectionSettings -> use_ssl; 
     1364        return _secure; 
    14251365} 
    14261366 
     
    14281368 
    14291369- (void) setProxyServer:(NSString *) address { 
    1430         IrssiLock(); 
    1431  
    1432         if( _chatConnectionSettings ) { 
    1433                 g_free_not_null( _chatConnectionSettings -> proxy ); 
    1434                 _chatConnectionSettings -> proxy = g_strdup( [self encodedBytesWithString:address] ); 
    1435         } 
    1436  
    1437         IrssiUnlock(); 
     1370        id old = _proxyServer; 
     1371        _proxyServer = [address copyWithZone:nil]; 
     1372        [old release]; 
    14381373} 
    14391374 
    14401375- (NSString *) proxyServer { 
    1441         if( ! _chatConnectionSettings ) return nil; 
    1442         return [self stringWithEncodedBytes:_chatConnectionSettings -> proxy]; 
     1376        return [[_proxyServer retain] autorelease]; 
    14431377} 
    14441378 
     
    14461380 
    14471381- (void) setProxyServerPort:(unsigned short) port { 
    1448         IrssiLock(); 
    1449         if( _chatConnectionSettings ) 
    1450                 _chatConnectionSettings -> proxy_port = port; 
    1451         IrssiUnlock(); 
     1382        _proxyServerPort = port; 
    14521383} 
    14531384 
    14541385- (unsigned short) proxyServerPort { 
    1455         if( ! _chatConnectionSettings ) return 0; 
    1456         return _chatConnectionSettings -> proxy_port; 
     1386        return _proxyServerPort; 
    14571387} 
    14581388 
     
    14861416        NSParameterAssert( raw != nil ); 
    14871417 
    1488         IrssiLock(); 
    1489         if( _chatConnection ) 
    1490                 irc_send_cmd_full( (IRC_SERVER_REC *) _chatConnection, [self encodedBytesWithString:raw], now, now, FALSE); 
    1491         IrssiUnlock(); 
     1418        const char *rawString = [self encodedBytesWithString:raw]; 
     1419        if( ! rawString ) return; 
     1420 
     1421        NSMutableData *data = [[NSMutableData allocWithZone:nil] initWithBytes:(void *)rawString length:strlen( rawString )]; 
     1422        [data appendBytes:"\x0D\x0A" length:2]; 
     1423 
     1424        [_chatConnection writeData:data withTimeout:-1. tag:0]; 
     1425        [data release]; 
    14921426} 
    14931427 
     
    15711505        NSParameterAssert( [[user nickname] length] > 0 ); 
    15721506 
    1573       IrssiLock(); 
     1507/*    IrssiLock(); 
    15741508        const char *mask = [self encodedBytesWithString:[NSString stringWithFormat:@"%@!*@*", [user nickname]]]; 
    15751509        if( ! notifylist_find( mask, NULL ) ) notifylist_add( mask, NULL, TRUE, 600 ); 
    1576         IrssiUnlock(); 
     1510        IrssiUnlock(); */ 
    15771511} 
    15781512 
     
    15811515        NSParameterAssert( [[user nickname] length] > 0 ); 
    15821516 
    1583       IrssiLock(); 
     1517/*    IrssiLock(); 
    15841518        notifylist_remove( [self encodedBytesWithString:[NSString stringWithFormat:@"%@!*@*", [user nickname]]] ); 
    1585         IrssiUnlock(); 
     1519        IrssiUnlock(); */ 
    15861520} 
    15871521 
     
    16111545 
    16121546                _awayMessage = [message copyWithZone:nil]; 
    1613               const char *msg = [[self class] _flattenedIRCStringForMessage:message withEncoding:[self encoding] andChatFormat:[self outgoingChatFormat]]; 
     1547/*            const char *msg = [[self class] _flattenedIRCStringForMessage:message withEncoding:[self encoding] andChatFormat:[self outgoingChatFormat]]; 
    16141548 
    16151549                IrssiLock(); 
    16161550                if( _chatConnection ) 
    16171551                        irc_send_cmdv( (IRC_SERVER_REC *) _chatConnection, "AWAY :%s", msg ); 
    1618                 IrssiUnlock(); 
     1552                IrssiUnlock(); */ 
    16191553        } else { 
    16201554                [[self localUser] _setStatus:MVChatUserAvailableStatus]; 
     
    16281562        unsigned int lag = 0; 
    16291563 
    1630       IrssiLock(); 
     1564/*    IrssiLock(); 
    16311565        if( _chatConnection ) 
    16321566                lag = _chatConnection -> lag; 
    1633         IrssiUnlock(); 
     1567        IrssiUnlock(); */ 
    16341568 
    16351569        return lag; 
    1636 } */ 
     1570} 
    16371571@end 
    16381572 
     
    16401574 
    16411575@implementation MVIRCChatConnection (MVIRCChatConnectionPrivate) 
     1576- (void) socket:(AsyncSocket *) sock willDisconnectWithError:(NSError *) error { 
     1577        NSLog(@"willDisconnectWithError: %@", error ); 
     1578        _status = MVChatConnectionServerDisconnectedStatus; 
     1579        if( ABS( [_lastConnectAttempt timeIntervalSinceNow] ) > 300. ) 
     1580                [self performSelector:@selector( connect ) withObject:nil afterDelay:5.]; 
     1581        [self scheduleReconnectAttemptEvery:30.]; 
     1582} 
     1583 
     1584- (void) socketDidDisconnect:(AsyncSocket *) sock { 
     1585        if( _status != MVChatConnectionServerDisconnectedStatus ) 
     1586                _status = MVChatConnectionDisconnectedStatus; 
     1587        [self _didDisconnect]; 
     1588} 
     1589 
     1590- (void) socket:(AsyncSocket *) sock didConnectToHost:(NSString *) host port:(UInt16) port { 
     1591        [self _didConnect]; 
     1592        [self _readNextMessageFromServer]; 
     1593} 
     1594 
     1595- (void) _readNextMessageFromServer { 
     1596        static NSData *delimeter = nil; 
     1597        if( ! delimeter ) delimeter = [[NSData allocWithZone:nil] initWithBytes:"\x0D\x0A" length:2]; 
     1598        [_chatConnection readDataToData:delimeter withTimeout:-1. tag:0]; 
     1599} 
     1600 
     1601- (void) socket:(AsyncSocket *) sock didReadData:(NSData *) data withTag:(long) tag { 
     1602        NSString *rawString = [[NSString allocWithZone:nil] initWithData:data encoding:[self encoding]]; 
     1603        char *line = (char *)[(NSMutableData *)data mutableBytes]; 
     1604        unsigned int len = [data length]; 
     1605 
     1606        char *sender = NULL; 
     1607        char *user = NULL; 
     1608        char *host = NULL; 
     1609        char *command = NULL; 
     1610        char *currentParameter = NULL; 
     1611        NSMutableArray *parameters = [[NSMutableArray allocWithZone:nil] initWithCapacity:10]; 
     1612 
     1613        if( len <= 2 || len > 512 ) 
     1614                goto end; // bad message 
     1615 
     1616        BOOL done = NO; 
     1617        if( *line != '\r' && ! done ) { 
     1618                if( *line == ':' ) { 
     1619                        // prefix: ':' <sender> [ '!' <user> ] [ '@' <host> ] ' ' { ' ' } 
     1620                        sender = ++line; 
     1621                        while( *line != '\r' && *line != ' ' && *line != '!' && *line != '@' ) line++; 
     1622                        if( *line == '\r' ) done = YES; 
     1623 
     1624                        if( *line == '!' ) { 
     1625                                *line++ = '\0'; 
     1626                                user = line; 
     1627                                while( *line != '\r' && *line != ' ' && *line != '@' && ! done ) line++; 
     1628                                if( *line == '\r' ) done = YES; 
     1629                                if( *line != '@' ) *line = '\0'; 
     1630                        } 
     1631 
     1632                        if( *line == '@' ) { 
     1633                                *line++ = '\0'; 
     1634                                host = line; 
     1635                                while( *line != '\r' && *line != ' ' && ! done ) line++; 
     1636                                if( *line == '\r' ) done = YES; 
     1637                                *line = '\0'; 
     1638                        } 
     1639 
     1640                        if( *line == ' ' ) { 
     1641                                *line++ = '\0'; 
     1642                                while( *line == ' ' && ! done ) line++; 
     1643                        } 
     1644                } 
     1645 
     1646                if( *line != '\r' && ! done ) { 
     1647                        // command: <letter> { <letter> } | <number> <number> <number> 
     1648                        // letter: 'a' ... 'z' | 'A' ... 'Z' 
     1649                        // number: '0' ... '9' 
     1650                        command = line; 
     1651                        while( *line != '\r' && *line != ' ' && ! done ) line++; 
     1652                        if( *line == ' ' ) { 
     1653                                *line++ = '\0'; 
     1654                                while( *line == ' ' && ! done ) line++; 
     1655                        } 
     1656                } 
     1657 
     1658                NSString *param = nil; 
     1659                while( *line != '\r' && ! done ) { 
     1660                        // params: [ ':' <trailing data> | <letter> { <letter> } ] [ ' ' { ' ' } ] [ <params> ] 
     1661                        currentParameter = NULL; 
     1662                        param = nil; 
     1663                        if( *line == ':' ) { 
     1664                                currentParameter = ++line; 
     1665                                while( *line != '\r' && ! done ) line++; 
     1666                                *line = '\0'; 
     1667                                done = YES; 
     1668                        } else { 
     1669                                currentParameter = line; 
     1670                                while( *line != '\r' && *line != ' ' && ! done ) line++; 
     1671                                if( *line == '\r' ) done = YES; 
     1672                                *line++ = '\0'; 
     1673                        } 
     1674 
     1675                        if( currentParameter )  
     1676                                param = [NSString stringWithBytes:currentParameter encoding:NSASCIIStringEncoding]; 
     1677                        if( param ) [parameters addObject:param]; 
     1678 
     1679                        while( *line == ' ' && ! done ) line++; 
     1680                } 
     1681        } 
     1682 
     1683end: 
     1684        NSLog(@"%s %s %s %s %@", sender, user, host, command, [parameters description] ); 
     1685 
     1686        NSNotification *note = [NSNotification notificationWithName:MVChatConnectionGotRawMessageNotification object:self userInfo:[NSDictionary dictionaryWithObjectsAndKeys:rawString, @"message", [NSNumber numberWithBool:NO], @"outbound", nil]]; 
     1687        [[NSNotificationCenter defaultCenter] postNotification:note]; 
     1688        [rawString release]; 
     1689 
     1690        [parameters release]; 
     1691        [self _readNextMessageFromServer]; 
     1692} 
     1693 
    16421694/* + (MVIRCChatConnection *) _connectionForServer:(SERVER_REC *) server { 
    16431695        if( ! server ) return nil;