Changeset 3539

Show
Ignore:
Timestamp:
01/07/07 02:39:56 (2 years ago)
Author:
timothy
Message:

Adds DCC chat support. You can start a chat by using the context menu or the /dcc chat <nick> command. #34

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Additions/NSStringAdditions.h

    r3517 r3539  
    66+ (unsigned long) scriptTypedEncodingFromStringEncoding:(NSStringEncoding) encoding; 
    77+ (NSStringEncoding) stringEncodingFromScriptTypedEncoding:(unsigned long) encoding; 
     8 
     9- (BOOL) isCaseInsensitiveEqualToString:(NSString *) string; 
     10- (BOOL) hasCaseInsensitivePrefix:(NSString *) prefix; 
     11- (BOOL) hasCaseInsensitiveSuffix:(NSString *) suffix; 
     12- (BOOL) hasCaseInsensitiveSubstring:(NSString *) substring; 
    813 
    914- (NSString *) stringByEncodingXMLSpecialCharactersAsEntities; 
  • trunk/Additions/NSStringAdditions.m

    r3517 r3539  
    212212#pragma mark - 
    213213 
     214- (BOOL) isCaseInsensitiveEqualToString:(NSString *) string { 
     215        return [self compare:string options:NSCaseInsensitiveSearch range:NSMakeRange( 0, [self length] ) locale:nil] == NSOrderedSame; 
     216} 
     217 
     218- (BOOL) hasCaseInsensitivePrefix:(NSString *) prefix { 
     219        return [self rangeOfString:prefix options:( NSCaseInsensitiveSearch | NSAnchoredSearch ) range:NSMakeRange( 0, [self length] ) locale:nil].location != NSNotFound; 
     220} 
     221 
     222- (BOOL) hasCaseInsensitiveSuffix:(NSString *) suffix { 
     223        return [self rangeOfString:suffix options:( NSCaseInsensitiveSearch | NSBackwardsSearch | NSAnchoredSearch ) range:NSMakeRange( 0, [self length] ) locale:nil].location != NSNotFound; 
     224} 
     225 
     226- (BOOL) hasCaseInsensitiveSubstring:(NSString *) substring { 
     227        return [self rangeOfString:substring options:NSCaseInsensitiveSearch range:NSMakeRange( 0, [self length] ) locale:nil].location != NSNotFound; 
     228} 
     229 
     230#pragma mark - 
     231 
    214232- (NSString *) stringByEncodingXMLSpecialCharactersAsEntities { 
    215233        NSMutableString *result = [self mutableCopyWithZone:nil]; 
  • trunk/Chat Core.exp

    r3515 r3539  
    44.objc_class_name_MVChatUser 
    55.objc_class_name_MVChatUserWatchRule 
     6.objc_class_name_MVDirectChatConnection 
    67.objc_class_name_MVDownloadFileTransfer 
    78.objc_class_name_MVFileTransfer 
     
    8384_MVChatUserWatchRuleMatchedNotification 
    8485_MVChatUserWatchRuleRemovedMatchedUserNotification 
     86_MVDirectChatConnectionDidConnectNotification 
     87_MVDirectChatConnectionDidDisconnectNotification 
     88_MVDirectChatConnectionDidNotConnectNotification 
     89_MVDirectChatConnectionErrorDomain 
     90_MVDirectChatConnectionErrorOccurredNotification 
     91_MVDirectChatConnectionGotMessageNotification 
     92_MVDirectChatConnectionOfferNotification 
    8593_MVDownloadFileTransferOfferNotification 
    8694_MVFileTransferErrorDomain 
  • trunk/Chat Core.xcodeproj/project.pbxproj

    r3537 r3539  
    2020                1C5A233F06FA4FEE00A51F10 /* libsilc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C5A233D06FA4FEE00A51F10 /* libsilc.framework */; }; 
    2121                1C5A234006FA4FEE00A51F10 /* libsilcclient.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C5A233E06FA4FEE00A51F10 /* libsilcclient.framework */; }; 
     22                1C5A491E0B50B7C000BC8CAD /* MVDirectChatConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C9C13370B50A7AC005F9F28 /* MVDirectChatConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 
    2223                1C63E9ED086E59D700A40DD4 /* ChatCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C63E9EC086E59D700A40DD4 /* ChatCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; 
    2324                1C668DBA07BF9C4C008400F7 /* NSScannerAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C668DB807BF9C4C008400F7 /* NSScannerAdditions.m */; }; 
     
    4445                1C943AAB063C260800618CD9 /* MVFileTransfer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C943AA9063C260800618CD9 /* MVFileTransfer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 
    4546                1C943AAC063C260800618CD9 /* MVFileTransfer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C943AAA063C260800618CD9 /* MVFileTransfer.m */; }; 
     47                1C9C133A0B50A7AC005F9F28 /* MVDirectChatConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C9C13380B50A7AC005F9F28 /* MVDirectChatConnection.m */; }; 
    4648                1C9CF4FE0615091400330D8D /* MVChatPluginManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C2EF7EB0427A40B00000102 /* MVChatPluginManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 
    4749                1C9CF4FF0615091500330D8D /* MVChatPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C2EF7EC0427A40B00000102 /* MVChatPluginManager.m */; }; 
     
    115117                1C943AAA063C260800618CD9 /* MVFileTransfer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MVFileTransfer.m; path = "Chat Core/MVFileTransfer.m"; sourceTree = "<group>"; }; 
    116118                1C9AE8E0086A5218008ED7AD /* Common Settings.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "Common Settings.xcconfig"; path = "Settings/Common Settings.xcconfig"; sourceTree = "<group>"; }; 
     119                1C9C13370B50A7AC005F9F28 /* MVDirectChatConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MVDirectChatConnection.h; path = "Chat Core/MVDirectChatConnection.h"; sourceTree = "<group>"; }; 
     120                1C9C13380B50A7AC005F9F28 /* MVDirectChatConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MVDirectChatConnection.m; path = "Chat Core/MVDirectChatConnection.m"; sourceTree = "<group>"; }; 
     121                1C9C14170B50B3AB005F9F28 /* MVDirectChatConnectionPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MVDirectChatConnectionPrivate.h; path = "Chat Core/MVDirectChatConnectionPrivate.h"; sourceTree = "<group>"; }; 
    117122                1CCA517E0598AFBA00F0A4CD /* ChatCore.scriptSuite */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = ChatCore.scriptSuite; path = Resources/ChatCore.scriptSuite; sourceTree = "<group>"; }; 
    118123                1CCA517F0598AFBA00F0A4CD /* ChatCore.scriptTerminology */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = ChatCore.scriptTerminology; path = Resources/ChatCore.scriptTerminology; sourceTree = "<group>"; }; 
     
    220225                                1C74433B06FE3AB3009AA696 /* MVIRCFileTransfer.m */, 
    221226                                1C74433A06FE3AB3009AA696 /* MVIRCFileTransfer.h */, 
    222                                 1C0FE8A90B4F647D00855B9C /* MVDirectClientConnection.m */, 
    223                                 1C0FE8A80B4F647D00855B9C /* MVDirectClientConnection.h */, 
    224227                                1CD62AA10962114500BD1DD2 /* MVIRCNumerics.h */, 
    225228                        ); 
     
    278281                                1C943AA9063C260800618CD9 /* MVFileTransfer.h */, 
    279282                                1CE4632E095ECDE600AB7732 /* MVFileTransferPrivate.h */, 
     283                                1C0FE8A90B4F647D00855B9C /* MVDirectClientConnection.m */, 
     284                                1C0FE8A80B4F647D00855B9C /* MVDirectClientConnection.h */, 
     285                                1C9C13380B50A7AC005F9F28 /* MVDirectChatConnection.m */, 
     286                                1C9C13370B50A7AC005F9F28 /* MVDirectChatConnection.h */, 
     287                                1C9C14170B50B3AB005F9F28 /* MVDirectChatConnectionPrivate.h */, 
    280288                                1C2EF7EC0427A40B00000102 /* MVChatPluginManager.m */, 
    281289                                1C2EF7EB0427A40B00000102 /* MVChatPluginManager.h */, 
     
    355363                                1C8AAEFE09D69F2700CF29EB /* MVChatUserWatchRule.h in Headers */, 
    356364                                1C3560060B4CCE95008A93FA /* MVUtilities.h in Headers */, 
     365                                1C5A491E0B50B7C000BC8CAD /* MVDirectChatConnection.h in Headers */, 
    357366                        ); 
    358367                        runOnlyForDeploymentPostprocessing = 0; 
     
    480489                                1C8AAEFF09D69F2700CF29EB /* MVChatUserWatchRule.m in Sources */, 
    481490                                1C0FE8AB0B4F647D00855B9C /* MVDirectClientConnection.m in Sources */, 
     491                                1C9C133A0B50A7AC005F9F28 /* MVDirectChatConnection.m in Sources */, 
    482492                        ); 
    483493                        runOnlyForDeploymentPostprocessing = 0; 
  • trunk/Chat Core/ChatCore.h

    r3530 r3539  
    66#import <ChatCore/MVChatUserWatchRule.h> 
    77#import <ChatCore/MVFileTransfer.h> 
     8#import <ChatCore/MVDirectChatConnection.h> 
    89#import <ChatCore/MVChatPluginManager.h> 
    910 
  • trunk/Chat Core/MVChatConnection.m

    r3530 r3539  
    10241024 
    10251025        while( ( user = [enumerator nextObject] ) ) 
    1026                 if( [[user nickname] caseInsensitiveCompare:name] == NSOrderedSame
     1026                if( [[user nickname] isCaseInsensitiveEqualToString:name]
    10271027                        return user; 
    10281028 
  • trunk/Chat Core/MVChatRoom.m

    r3530 r3539  
    669669 
    670670        while( ( user = [enumerator nextObject] ) ) 
    671                 if( [[user nickname] caseInsensitiveCompare:memberName] == NSOrderedSame
     671                if( [[user nickname] isCaseInsensitiveEqualToString:memberName]
    672672                        return user; 
    673673 
  • trunk/Chat Core/MVDirectClientConnection.h

    r3537 r3539  
    22 
    33@class AsyncSocket; 
     4 
     5NSString *MVDCCFriendlyAddress( NSString *address ); 
    46 
    57@interface MVDirectClientConnection : NSObject { 
  • trunk/Chat Core/MVDirectClientConnection.m

    r3537 r3539  
    55#import "MVFileTransfer.h" 
    66#import "MVUtilities.h" 
     7 
     8#import <arpa/inet.h> 
     9 
     10NSString *MVDCCFriendlyAddress( NSString *address ) { 
     11        NSURL *url = [NSURL URLWithString:@"http://colloquy.info/ip.php"]; 
     12        NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:3.]; 
     13        NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL]; 
     14        if( [result length] >= 6 && [result length] <= 40 ) // should be a valid IPv4 or IPv6 address 
     15                address = [[[NSString allocWithZone:nil] initWithData:result encoding:NSASCIIStringEncoding] autorelease]; 
     16 
     17        if( [address rangeOfString:@"."].location != NSNotFound ) 
     18                return [NSString stringWithFormat:@"%lu", ntohl( inet_addr( [address UTF8String] ) )]; 
     19        return address; 
     20} 
    721 
    822static int natTraversalStatus( tr_upnp_t *upnp, tr_natpmp_t *natpmp ) { 
  • trunk/Chat Core/MVIRCChatConnection.m

    r3537 r3539  
    44#import "MVIRCFileTransfer.h" 
    55#import "MVIRCNumerics.h" 
     6#import "MVDirectChatConnectionPrivate.h" 
    67 
    78#import "AsyncSocket.h" 
     
    15071508                                        NSString *msg = [self _newStringWithBytes:[msgData bytes] length:[msgData length]]; 
    15081509 
    1509                                         if( [msg rangeOfString:@"NickServ"].location != NSNotFound && [msg rangeOfString:@"IDENTIFY"].location != NSNotFound ) { 
     1510                                        if( [msg hasCaseInsensitiveSubstring:@"NickServ"] && [msg hasCaseInsensitiveSubstring:@"IDENTIFY"] ) { 
    15101511                                                if( ! [self nicknamePassword] ) { 
    15111512                                                        [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatConnectionNeedNicknamePasswordNotification object:self userInfo:nil]; 
    15121513                                                } else [self sendRawMessageImmediatelyWithFormat:@"NickServ IDENTIFY %@", [self nicknamePassword]]; 
    1513                                         } else if( [msg rangeOfString:@"Password accepted"].location != NSNotFound ) { 
     1514                                        } else if( [msg hasCaseInsensitiveSubstring:@"password accepted"] ) { 
    15141515                                                [[self localUser] _setIdentified:YES]; 
    1515                                         } else if( [msg rangeOfString:@"authentication required"].location != NSNotFound ) { 
     1516                                        } else if( [msg hasCaseInsensitiveSubstring:@"authentication required"] || [msg hasCaseInsensitiveSubstring:@"nickname is owned"] ) { 
    15161517                                                [[self localUser] _setIdentified:NO]; 
    15171518                                        } 
     
    15391540 
    15401541        NSString *command = [self _newStringWithBytes:current length:(line - current)]; 
    1541         NSMutableData *arguments = nil; 
     1542        NSData *arguments = nil; 
    15421543        if( line != end ) { 
    15431544                line++; 
    1544                 arguments = [[NSMutableData allocWithZone:nil] initWithBytes:line length:(end - line)]; 
    1545         } 
    1546  
    1547         if( [command caseInsensitiveCompare:@"ACTION"] == NSOrderedSame && arguments ) { 
     1545                arguments = [[NSData allocWithZone:nil] initWithBytes:line length:(end - line)]; 
     1546        } 
     1547 
     1548        if( [command isCaseInsensitiveEqualToString:@"ACTION"] && arguments ) { 
    15481549                // special case ACTION and send it out like a message with the action flag 
    15491550                if( room ) [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatRoomGotMessageNotification object:room userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", arguments, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"action", nil]]; 
     
    15741575 
    15751576        if( request ) { 
    1576                 if( [command caseInsensitiveCompare:@"VERSION"] == NSOrderedSame ) { 
     1577                if( [command isCaseInsensitiveEqualToString:@"VERSION"] ) { 
    15771578                        NSDictionary *systemVersion = [[NSDictionary allocWithZone:nil] initWithContentsOfFile:@"/System/Library/CoreServices/ServerVersion.plist"]; 
    15781579                        if( ! [systemVersion count] ) systemVersion = [[NSDictionary allocWithZone:nil] initWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; 
     
    15921593                        [reply release]; 
    15931594                        [systemVersion release]; 
    1594                 } else if( [command caseInsensitiveCompare:@"TIME"] == NSOrderedSame ) { 
     1595                } else if( [command isCaseInsensitiveEqualToString:@"TIME"] ) { 
    15951596                        [sender sendSubcodeReply:command withArguments:[[NSDate date] description]]; 
    1596                 } else if( [command caseInsensitiveCompare:@"PING"] == NSOrderedSame ) { 
     1597                } else if( [command isCaseInsensitiveEqualToString:@"PING"] ) { 
    15971598                        // only reply with packets less than 100 bytes, anything over that is bad karma 
    15981599                        if( [arguments length] < 100 ) [sender sendSubcodeReply:command withArguments:arguments]; 
    1599                 } else if( [command caseInsensitiveCompare:@"DCC"] == NSOrderedSame ) { 
     1600                } else if( [command isCaseInsensitiveEqualToString:@"DCC"] ) { 
    16001601                        NSString *msg = [self _newStringWithBytes:[arguments bytes] length:[arguments length]]; 
    16011602                        NSString *subCommand = nil; 
     
    16141615                        } 
    16151616 
    1616                         if( [subCommand caseInsensitiveCompare:@"SEND"] == NSOrderedSame ) { 
     1617                        if( [subCommand isCaseInsensitiveEqualToString:@"SEND"] ) { 
    16171618                                NSString *address = nil; 
    16181619                                int port = 0; 
     
    16751676                                        [transfer release]; 
    16761677                                } 
    1677                         } else if( [subCommand caseInsensitiveCompare:@"ACCEPT"] == NSOrderedSame ) { 
     1678                        } else if( [subCommand isCaseInsensitiveEqualToString:@"ACCEPT"] ) { 
    16781679                                BOOL passive = NO; 
    16791680                                int port = 0; 
     
    17091710                                        } 
    17101711                                } 
    1711                         } else if( [subCommand caseInsensitiveCompare:@"RESUME"] == NSOrderedSame ) { 
     1712                        } else if( [subCommand isCaseInsensitiveEqualToString:@"RESUME"] ) { 
    17121713                                BOOL passive = NO; 
    17131714                                int port = 0; 
     
    17431744                                        } 
    17441745                                } 
     1746                        } else if( [subCommand isCaseInsensitiveEqualToString:@"CHAT"] ) { 
     1747                                NSString *address = nil; 
     1748                                int port = 0; 
     1749 
     1750                                [scanner scanUpToCharactersFromSet:whitespace intoString:&address]; 
     1751                                [scanner scanInt:&port]; 
     1752 
     1753                                if( [address rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@".:"]].location == NSNotFound ) { 
     1754                                        unsigned int ip4 = 0; 
     1755                                        sscanf( [address UTF8String], "%u", &ip4 ); 
     1756                                        address = [NSString stringWithFormat:@"%lu.%lu.%lu.%lu", (ip4 & 0xff000000) >> 24, (ip4 & 0x00ff0000) >> 16, (ip4 & 0x0000ff00) >> 8, (ip4 & 0x000000ff)]; 
     1757                                } 
     1758 
     1759                                NSHost *host = [NSHost hostWithAddress:address]; 
     1760 
     1761                                if( [fileName isCaseInsensitiveEqualToString:@"CHAT"] || [fileName isCaseInsensitiveEqualToString:@"C H A T"] ) { 
     1762                                        MVDirectChatConnection *directChatConnection = [(MVDirectChatConnection *)[MVDirectChatConnection allocWithZone:nil] initWithUser:sender]; 
     1763                                        [directChatConnection _setPassive:NO]; 
     1764                                        [directChatConnection _setHost:host]; 
     1765                                        [directChatConnection _setPort:port]; 
     1766 
     1767                                        [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVDirectChatConnectionOfferNotification object:directChatConnection userInfo:[NSDictionary dictionaryWithObjectsAndKeys:sender, @"user", nil]]; 
     1768 
     1769                                        [directChatConnection release]; 
     1770                                } 
    17451771                        } 
    17461772 
    17471773                        [msg release]; 
    1748                 } else if( [command caseInsensitiveCompare:@"CLIENTINFO"] == NSOrderedSame ) { 
     1774                } else if( [command isCaseInsensitiveEqualToString:@"CLIENTINFO"] ) { 
    17491775                        // make this extnesible later with a plugin registration method 
    17501776                        [sender sendSubcodeReply:command withArguments:@"VERSION TIME PING DCC CLIENTINFO"]; 
    17511777                } 
    17521778        } else { 
    1753                 if( [command caseInsensitiveCompare:@"DCC"] == NSOrderedSame ) { 
     1779                if( [command isCaseInsensitiveEqualToString:@"DCC"] ) { 
    17541780                        NSString *msg = [self _newStringWithBytes:[arguments bytes] length:[arguments length]]; 
    17551781                        NSString *subCommand = nil; 
     
    17601786                        [scanner scanUpToCharactersFromSet:whitespace intoString:&subCommand]; 
    17611787 
    1762                         if( [subCommand caseInsensitiveCompare:@"REJECT"] == NSOrderedSame ) { 
     1788                        if( [subCommand isCaseInsensitiveEqualToString:@"REJECT"] ) { 
    17631789                                [scanner scanUpToCharactersFromSet:whitespace intoString:&subCommand]; 
    17641790 
    1765                                 if( [subCommand caseInsensitiveCompare:@"SEND"] == NSOrderedSame ) { 
     1791                                if( [subCommand isCaseInsensitiveEqualToString:@"SEND"] ) { 
    17661792                                        NSString *fileName = nil; 
    17671793                                        BOOL portKnown = NO; 
     
    17961822                                                                continue; 
    17971823 
    1798                                                         BOOL fileMatches = ( [[[(MVUploadFileTransfer *)transfer source] lastPathComponent] caseInsensitiveCompare:fileName] == NSOrderedSame ); 
     1824                                                        BOOL fileMatches = ( [[[(MVUploadFileTransfer *)transfer source] lastPathComponent] isCaseInsensitiveEqualToString:fileName] ); 
    17991825                                                        if( ! fileMatches && ! portKnown && ! passive ) 
    18001826                                                                continue; 
     
    21882214                        if( [_lastSentIsonNicknames containsObject:nickLower] ) { 
    21892215                                MVChatUser *user = [self chatUserWithUniqueIdentifier:nick]; 
    2190                                 if( ! [[user nickname] isEqualToString:nick] && [[user nickname] caseInsensitiveCompare:nick] == NSOrderedSame
     2216                                if( ! [[user nickname] isEqualToString:nick] && [[user nickname] isCaseInsensitiveEqualToString:nick]
    21912217                                        [user _setNickname:nick]; // nick differed only in case, change to the proper case 
    21922218                                if( [[user dateUpdated] timeIntervalSinceNow] < -JVWatchedUserWHOISDelay || ! [user dateUpdated] ) 
     
    22172243 
    22182244                        MVChatUser *user = [self chatUserWithUniqueIdentifier:nick]; 
    2219                         if( ! [[user nickname] isEqualToString:nick] && [[user nickname] caseInsensitiveCompare:nick] == NSOrderedSame
     2245                        if( ! [[user nickname] isEqualToString:nick] && [[user nickname] isCaseInsensitiveEqualToString:nick]
    22202246                                [user _setNickname:nick]; // nick differed only in case, change to the proper case 
    22212247                        [self _markUserAsOnline:user]; 
     
    24502476                NSString *nick = [parameters objectAtIndex:1]; 
    24512477                MVChatUser *user = [self chatUserWithUniqueIdentifier:nick]; 
    2452                 if( ! [[user nickname] isEqualToString:nick] && [[user nickname] caseInsensitiveCompare:nick] == NSOrderedSame
     2478                if( ! [[user nickname] isEqualToString:nick] && [[user nickname] isCaseInsensitiveEqualToString:nick]
    24532479                        [user _setNickname:nick]; // nick differed only in case, change to the proper case 
    24542480                [user _setUsername:[parameters objectAtIndex:2]]; 
     
    25522578        if( [parameters count] == 3 ) { 
    25532579                NSString *comment = [self _stringFromPossibleData:[parameters objectAtIndex:2]]; 
    2554                 if( [comment rangeOfString:@"identified" options:NSCaseInsensitiveSearch].location != NSNotFound ) { 
     2580                if( [comment hasCaseInsensitiveSubstring:@"identified"] ) { 
    25552581                        MVChatUser *user = [self chatUserWithUniqueIdentifier:[parameters objectAtIndex:1]]; 
    25562582                        [user _setIdentified:YES]; 
     
    25942620        if( [parameters count] >= 2 ) { 
    25952621                NSString *command = [parameters objectAtIndex:1]; 
    2596                 if( [command caseInsensitiveCompare:@"NickServ"] == NSOrderedSame ) { 
     2622                if( [command isCaseInsensitiveEqualToString:@"NickServ"] ) { 
    25972623                        // the NickServ command isn't supported, this is an older server 
    25982624                        // lets send a private message to NickServ to identify 
  • trunk/Chat Core/MVIRCChatUser.m

    r3512 r3539  
    110110        NSString *command = [[notification userInfo] objectForKey:@"command"]; 
    111111        NSData *arguments = [[notification userInfo] objectForKey:@"arguments"]; 
    112         if( [command caseInsensitiveCompare:@"PING"] == NSOrderedSame ) { 
     112        if( [command isCaseInsensitiveEqualToString:@"PING"] ) { 
    113113                NSTimeInterval diff = [[NSDate date] timeIntervalSinceDate:[self attributeForKey:@"MVChatUserPingSendDateAttribute"]]; 
    114114                [self setAttribute:[NSNumber numberWithDouble:diff] forKey:MVChatUserPingAttribute]; 
    115115                [self setAttribute:nil forKey:@"MVChatUserPingSendDateAttribute"]; 
    116         } else if( [command caseInsensitiveCompare:@"VERSION"] == NSOrderedSame ) { 
     116        } else if( [command isCaseInsensitiveEqualToString:@"VERSION"] ) { 
    117117                NSString *info = [[NSString allocWithZone:nil] initWithData:arguments encoding:[[self connection] encoding]]; 
    118118                [self setAttribute:info forKey:MVChatUserClientInfoAttribute]; 
    119119                [info release]; 
    120         } else if( [command caseInsensitiveCompare:@"TIME"] == NSOrderedSame ) { 
     120        } else if( [command isCaseInsensitiveEqualToString:@"TIME"] ) { 
    121121                NSString *date = [[NSString allocWithZone:nil] initWithData:arguments encoding:[[self connection] encoding]]; 
    122122                NSCalendarDate *localThere = [NSCalendarDate dateWithNaturalLanguageString:date]; 
  • trunk/Chat Core/MVIRCFileTransfer.m

    r3537 r3539  
    1 #import <arpa/inet.h> 
    2  
    31#import "MVIRCFileTransfer.h" 
     2 
     3#import "AsyncSocket.h" 
     4#import "InterThreadMessaging.h" 
     5#import "MVChatUser.h" 
    46#import "MVDirectClientConnection.h" 
    57#import "MVIRCChatConnection.h" 
    6 #import "MVChatUser.h" 
    78#import "MVUtilities.h" 
    89#import "NSNotificationAdditions.h" 
    9 #import "AsyncSocket.h" 
    10 #import "InterThreadMessaging.h" 
    1110#import "Transmission.h" 
    1211 
     12#import <arpa/inet.h> 
     13 
    1314#define DCCPacketSize 4096 
    14  
    15 static NSString *dccFriendlyAddress( NSString *address ) { 
    16         NSURL *url = [NSURL URLWithString:@"http://colloquy.info/ip.php"]; 
    17         NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:3.]; 
    18         NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL]; 
    19         if( [result length] >= 6 && [result length] <= 40 ) // should be a valid IPv4 or IPv6 address 
    20                 address = [[[NSString allocWithZone:nil] initWithData:result encoding:NSASCIIStringEncoding] autorelease]; 
    21  
    22         if( [address rangeOfString:@"."].location != NSNotFound ) 
    23                 return [NSString stringWithFormat:@"%lu", ntohl( inet_addr( [address UTF8String] ) )]; 
    24         return address; 
    25 } 
    26  
    27 #pragma mark - 
    2815 
    2916@implementation MVIRCUploadFileTransfer 
     
    121108 
    122109- (void) directClientConnection:(MVDirectClientConnection *) connection acceptingConnectionsToHost:(NSString *) host port:(unsigned short) port { 
    123         NSString *address = dccFriendlyAddress( host ); 
     110        NSString *address = MVDCCFriendlyAddress( host ); 
    124111        [self _setPort:port]; 
    125112 
     
    336323 
    337324- (void) directClientConnection:(MVDirectClientConnection *) connection acceptingConnectionsToHost:(NSString *) host port:(unsigned short) port { 
    338         NSString *address = dccFriendlyAddress( host ); 
     325        NSString *address = MVDCCFriendlyAddress( host ); 
    339326        [self _setPort:port]; 
    340327 
  • trunk/Controllers/JVChatController.h

    r3418 r3539  
    44@class MVChatRoom; 
    55@class MVChatUser; 
     6@class MVDirectChatConnection; 
    67@class JVChatWindowController; 
    78@class JVChatRoomPanel; 
     
    3839- (JVDirectChatPanel *) chatViewControllerForUser:(MVChatUser *) user ifExists:(BOOL) exists; 
    3940- (JVDirectChatPanel *) chatViewControllerForUser:(MVChatUser *) user ifExists:(BOOL) exists userInitiated:(BOOL) requested; 
     41- (JVDirectChatPanel *) chatViewControllerForDirectChatConnection:(MVDirectChatConnection *) connection ifExists:(BOOL) exists; 
     42- (JVDirectChatPanel *) chatViewControllerForDirectChatConnection:(MVDirectChatConnection *) connection ifExists:(BOOL) exists userInitiated:(BOOL) initiated; 
    4043- (JVChatTranscriptPanel *) chatViewControllerForTranscript:(NSString *) filename; 
    4144- (JVChatConsolePanel *) chatConsoleForConnection:(MVChatConnection *) connection ifExists:(BOOL) exists; 
  • trunk/Controllers/JVChatController.m

    r3496 r3539  
    9090                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _joinedRoom: ) name:MVChatRoomJoinedNotification object:nil]; 
    9191                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _invitedToRoom: ) name:MVChatRoomInvitedNotification object:nil]; 
     92                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _invitedToDirectChat: ) name:MVDirectChatConnectionOfferNotification object:nil]; 
    9293                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _gotBeep: ) name:MVChatConnectionGotBeepNotification object:nil]; 
    9394                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _gotPrivateMessage: ) name:MVChatConnectionGotPrivateMessageNotification object:nil]; 
    9495                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _gotRoomMessage: ) name:MVChatRoomGotMessageNotification object:nil]; 
     96                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _gotDirectChatMessage: ) name:MVDirectChatConnectionGotMessageNotification object:nil]; 
    9597                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector( _errorOccurred: ) name:MVChatConnectionErrorNotification object:nil]; 
    9698 
     
    325327} 
    326328 
     329- (JVDirectChatPanel *) chatViewControllerForDirectChatConnection:(MVDirectChatConnection *) connection ifExists:(BOOL) exists { 
     330        return [self chatViewControllerForDirectChatConnection:connection ifExists:exists userInitiated:YES]; 
     331} 
     332 
     333- (JVDirectChatPanel *) chatViewControllerForDirectChatConnection:(MVDirectChatConnection *) connection ifExists:(BOOL) exists userInitiated:(BOOL) initiated { 
     334        NSParameterAssert( connection != nil ); 
     335 
     336        NSEnumerator *enumerator = [_chatControllers objectEnumerator]; 
     337        id ret = nil; 
     338 
     339        while( ( ret = [enumerator nextObject] ) ) 
     340                if( [ret isMemberOfClass:[JVDirectChatPanel class]] && [[ret target] isEqual:connection] ) 
     341                        break; 
     342 
     343        if( ! ret && ! exists ) { 
     344                if( ( ret = [[[JVDirectChatPanel alloc] initWithTarget:connection] autorelease] ) ) { 
     345                        [_chatControllers addObject:ret]; 
     346                        [self addViewControllerToPreferedWindowController:ret userInitiated:initiated]; 
     347                } 
     348        } 
     349 
     350        return ret; 
     351} 
     352 
    327353- (JVChatTranscriptPanel *) chatViewControllerForTranscript:(NSString *) filename { 
    328354        id ret = nil; 
     
    486512        NSString *message = [NSString stringWithFormat:NSLocalizedString( @"You were invited to join %@ by %@. Would you like to accept this invitation and join this room?", "you were invited to join a chat room status message" ), room, [user nickname]]; 
    487513 
    488         if( NSRunInformationalAlertPanel( title, message, NSLocalizedString( @"Join", "join button" ), NSLocalizedString( @"Decline", "decline button" ), nil ) == NSOKButton ) 
    489                 [connection joinChatRoomNamed:room]; 
    490  
    491514        NSMutableDictionary *context = [NSMutableDictionary dictionary]; 
    492515        [context setObject:NSLocalizedString( @"Invited to Chat", "bubble title invited to room" ) forKey:@"title"]; 
    493516        [context setObject:[NSString stringWithFormat:NSLocalizedString( @"You were invited to %@ by %@.", "bubble message invited to room" ), room, [user nickname]] forKey:@"description"]; 
    494517        [[JVNotificationController defaultController] performNotification:@"JVChatRoomInvite" withContextInfo:context]; 
     518 
     519        if( NSRunInformationalAlertPanel( title, message, NSLocalizedString( @"Join", "join button" ), NSLocalizedString( @"Decline", "decline button" ), nil ) == NSOKButton ) 
     520                [connection joinChatRoomNamed:room]; 
     521} 
     522 
     523- (void) _invitedToDirectChat:(NSNotification *) notification { 
     524        MVChatUser *user = [[notification userInfo] objectForKey:@"user"]; 
     525        MVDirectChatConnection *connection = [notification object]; 
     526 
     527        if( ! [[MVConnectionsController defaultController] managesConnection:[user connection]] ) return; 
     528 
     529        NSString *title = NSLocalizedString( @"Direct Chat Invite", "invited to direct chat title" ); 
     530        NSString *message = [NSString stringWithFormat:NSLocalizedString( @"You were invited to participate in a chat with %@. Would you like to accept this invitation?", "you were invited to a direct chat status message" ), [user nickname]]; 
     531 
     532        NSMutableDictionary *context = [NSMutableDictionary dictionary]; 
     533        [context setObject:NSLocalizedString( @"Invited to Direct Chat", "bubble title invited to direct chat" ) forKey:@"title"]; 
     534        [context setObject:[NSString stringWithFormat:NSLocalizedString( @"You were invited to participate in a chat with %@.", "bubble message invited to participate in a direct chat" ), [user nickname]] forKey:@"description"]; 
     535        [[JVNotificationController defaultController] performNotification:@"JVDirectChatInvite" withContextInfo:context]; 
     536 
     537        if( NSRunInformationalAlertPanel( title, message, NSLocalizedString( @"Accept", "accept button" ), NSLocalizedString( @"Decline", "decline button" ), nil ) == NSOKButton ) { 
     538                [self chatViewControllerForDirectChatConnection:connection ifExists:NO userInitiated:NO]; 
     539                [connection initiate]; 
     540        } 
    495541} 
    496542 
     
    507553        [context setObject:NSStringFromSelector( @selector( activate: ) ) forKey:@"action"]; 
    508554        [[JVNotificationController defaultController] performNotification:@"JVChatBeeped" withContextInfo:context]; 
     555} 
     556 
     557- (void) _gotDirectChatMessage:(NSNotification *) notification { 
     558        MVDirectChatConnection *connection = [notification object]; 
     559        NSData *message = [[notification userInfo] objectForKey:@"message"]; 
     560        MVChatUser *user = [connection user]; 
     561 
     562        if( ! [[MVConnectionsController defaultController] managesConnection:[user connection]] ) return; 
     563 
     564        if( ( [self shouldIgnoreUser:user withMessage:nil inView:nil] == JVNotIgnored ) ) { 
     565                JVDirectChatPanel *controller = [self chatViewControllerForDirectChatConnection:connection ifExists:NO userInitiated:NO]; 
     566                [controller addMessageToDisplay:message fromUser:user asAction:[[[notification userInfo] objectForKey:@"action"] boolValue] withIdentifier:[[notification userInfo] objectForKey:@"identifier"] andType:JVChatMessageNormalType]; 
     567        } 
     568} 
     569 
     570- (void) _gotRoomMessage:(NSNotification *) notification { 
     571        // we do this here to make sure we catch early messages right when we join (this includes dircproxy's dump) 
     572        MVChatRoom *room = [notification object]; 
     573        JVChatRoomPanel *controller = [self chatViewControllerForRoom:room ifExists:NO]; 
     574        [controller handleRoomMessageNotification:notification]; 
    509575} 
    510576 
     
    570636} 
    571637 
    572 - (void) _gotRoomMessage:(NSNotification *) notification { 
    573         // we do this here to make sure we catch early messages right when we join (this includes dircproxy's dump) 
    574         MVChatRoom *room = [notification object]; 
    575         JVChatRoomPanel *controller = [self chatViewControllerForRoom:room ifExists:NO]; 
    576         [controller handleRoomMessageNotification:notification]; 
    577 } 
    578  
    579638- (void) _errorOccurred:(NSNotification *) notification { 
    580639        NSError *error = [[notification userInfo] objectForKey:@"error"]; 
  • trunk/Panels/JVChatRoomMember.m

    r3538 r3539  
    7373- (NSComparisonResult) compareUsingStatus:(JVChatRoomMember *) member { 
    7474        NSComparisonResult retVal = NSOrderedSame; 
    75         unsigned long myStatus = 0, yourStatus = 0; 
    76  
    77         myStatus = ( [self serverOperator] ? 1 << 8 : [[_room target] modesForMemberUser:_user] & ~MVChatRoomMemberQuietedMode ); 
    78         yourStatus = ( [member serverOperator] ? 1 << 8 : [[[member room] target] modesForMemberUser:[member user]] & ~MVChatRoomMemberQuietedMode ); 
     75 
     76        unsigned long myStatus = ( [self serverOperator] ? 1 << 8 : [[_room target] modesForMemberUser:_user] & ~MVChatRoomMemberQuietedMode ); 
     77        unsigned long yourStatus = ( [member serverOperator] ? 1 << 8 : [[[member room] target] modesForMemberUser:[member user]] & ~MVChatRoomMemberQuietedMode ); 
    7978 
    8079        if( myStatus > yourStatus ) { 
  • trunk/Panels/JVDirectChatPanel.m

    r3496 r3539  
    157157                _target = [target retain]; 
    158158 
    159                 NSURL *connURL = [[self connection] url]; 
    160                 NSString *targetName = nil; 
    161  
    162                 if( [target respondsToSelector:@selector( name )] ) targetName = [(MVChatRoom *)target name]; 
    163                 else targetName = [target nickname]; 
    164  
    165                 NSURL *source = [[NSURL alloc] initWithScheme:[connURL scheme] host:[connURL host] path:[[connURL path] stringByAppendingString:[NSString stringWithFormat:@"/%@",targetName]]]; 
    166  
    167                 if( ( [self isMemberOfClass:[JVDirectChatPanel class]] && [[NSUserDefaults standardUserDefaults] boolForKey:@"JVLogPrivateChats"] ) || 
    168                         ( [self isMemberOfClass:[JVChatRoomPanel class]] && [[NSUserDefaults standardUserDefaults] boolForKey:@"JVLogChatRooms"] ) ) { 
    169                         NSString *logs = [[[NSUserDefaults standardUserDefaults] stringForKey:@"JVChatTranscriptFolder"] stringByStandardizingPath]; 
    170                         NSFileManager *fileManager = [NSFileManager defaultManager]; 
    171  
    172                         if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
    173  
    174                         int org = [[NSUserDefaults standardUserDefaults] integerForKey:@"JVChatTranscriptFolderOrganization"]; 
    175                         if( org == 1 ) { 
    176                                 logs = [logs stringByAppendingPathComponent:[[self connection] server]]; 
     159                if( [self connection] ) { 
     160                        NSURL *connURL = [[self connection] url]; 
     161                        NSString *targetName = nil; 
     162 
     163                        if( [target respondsToSelector:@selector( name )] ) 
     164                                targetName = [(MVChatRoom *)target name]; 
     165                        else if( [target respondsToSelector:@selector( nickname )] ) 
     166                                targetName = [(MVChatUser *)target nickname]; 
     167                        else targetName = [target description]; 
     168 
     169                        NSURL *source = [[NSURL alloc] initWithScheme:[connURL scheme] host:[connURL host] path:[[connURL path] stringByAppendingString:[NSString stringWithFormat:@"/%@", targetName]]]; 
     170 
     171                        if( ( [self isMemberOfClass:[JVDirectChatPanel class]] && [[NSUserDefaults standardUserDefaults] boolForKey:@"JVLogPrivateChats"] ) || 
     172                                ( [self isMemberOfClass:[JVChatRoomPanel class]] && [[NSUserDefaults standardUserDefaults] boolForKey:@"JVLogChatRooms"] ) ) { 
     173                                NSString *logs = [[[NSUserDefaults standardUserDefaults] stringForKey:@"JVChatTranscriptFolder"] stringByStandardizingPath]; 
     174                                NSFileManager *fileManager = [NSFileManager defaultManager]; 
     175 
    177176                                if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
    178                         } else if( org == 2 ) { 
    179                                 logs = [logs stringByAppendingPathComponent:[NSString stringWithFormat:@"%@ (%@)", [self target], [[self connection] server]]]; 
    180                                 if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
    181                         } else if( org == 3 ) { 
    182                                 logs = [logs stringByAppendingPathComponent:[[self connection] server]]; 
    183                                 if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
    184  
    185                                 logs = [logs stringByAppendingPathComponent:[self title]]; 
    186                                 if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
     177 
     178                                int org = [[NSUserDefaults standardUserDefaults] integerForKey:@"JVChatTranscriptFolderOrganization"]; 
     179                                if( org == 1 ) { 
     180                                        logs = [logs stringByAppendingPathComponent:[[self connection] server]]; 
     181                                        if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
     182                                } else if( org == 2 ) { 
     183                                        logs = [logs stringByAppendingPathComponent:[NSString stringWithFormat:@"%@ (%@)", [self target], [[self connection] server]]]; 
     184                                        if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
     185                                } else if( org == 3 ) { 
     186                                        logs = [logs stringByAppendingPathComponent:[[self connection] server]]; 
     187                                        if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
     188 
     189                                        logs = [logs stringByAppendingPathComponent:[self title]]; 
     190                                        if( ! [fileManager fileExistsAtPath:logs] ) [fileManager createDirectoryAtPath:logs attributes:nil]; 
     191                                } 
     192 
     193                                NSString *logName = nil; 
     194                                NSString *dateString = [[NSCalendarDate date] descriptionWithCalendarFormat:[[NSUserDefaults standardUserDefaults] stringForKey:NSShortDateFormatString]]; 
     195 
     196                                int session = [[NSUserDefaults standardUserDefaults] integerForKey:@"JVChatTranscriptSessionHandling"]; 
     197 
     198                                if( ! session ) { 
     199                                        BOOL nameFound = NO; 
     200                                        unsigned int i = 1; 
     201 
     202                                        if( org ) logName = [NSString stringWithFormat:@"%@.colloquyTranscript", [self target]]; 
     203                                        else logName = [NSString stringWithFormat:@"%@ (%@).colloquyTranscript", [self target], [[self connection] server]]; 
     204