Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #import <Foundation/Foundation.h>
- #import "TRPacket.h"
- #import "TRUtilities.h"
- #import "TRConnection.h"
- const NSString *kTRConnectionSettingsServer = @"kTRConnectionSettingsServer";
- const NSString *kTRConnectionSettingsPort = @"kTRConnectionSettingsPort";
- const NSString *kTRConnectionSettingsNickname = @"kTRConnectionSettingsNickname";
- const NSString *kTRConnectionSettingsAlternateNicknames = @"kTRConnectionSettingsAlternateNicknames";
- const NSString *kTRConnectionSettingsNicknamePassword = @"kTRConnectionSettingsNicknamePassword";
- const NSString *kTRConnectionSettingsUsername = @"kTRConnectionSettingsUsername";
- const NSString *kTRConnectionSettingsPassword = @"kTRConnectionSettingsPassword";
- const NSString *kTRConnectionSettingsRealname = @"kTRConnectionSettingsRealname";
- const NSString *kTRConnectionSettingsDelegate = @"kTRConnectionSettingsDelegate";
- @implementation TRConnection
- #pragma mark Initializing
- - (id)init {
- if (!(self = [super init])) return nil;
- _threadWaitLock = [[NSConditionLock allocWithZone:nil] initWithCondition:0];
- _status = TRConnectionDisconnectedStatus;
- _encoding = NSUTF8StringEncoding;
- [self setServer:@"irc.freenode.net"];
- [self setPort:6667];
- [self setNickname:@"TribUser"];
- [self setAlternateNicknames:[NSArray arrayWithObjects:@"TribUser_", @"TribUser__", nil]];
- [self setUsername:@"TribUser"];
- [self setRealname:@"Tribunal User"];
- return self;
- }
- - (id)initWithDictionary:(NSDictionary*)dict {
- if (!(self = [self init])) return nil;
- if ([dict objectForKey:@"kTRConnectionSettingsServer"]) [self setServer:[dict objectForKey:@"kTRConnectionSettingsServer"]];
- if ([dict objectForKey:@"kTRConnectionSettingsPort"]) [self setPort:[[dict objectForKey:@"kTRConnectionSettingsPort"] intValue]];
- if ([dict objectForKey:@"kTRConnectionSettingsNickname"]) [self setNickname:[dict objectForKey:@"kTRConnectionSettingsNickname"]];
- if ([dict objectForKey:@"kTRConnectionSettingsAlternateNicknames"]) [self setAlternateNicknames:[dict objectForKey:@"kTRConnectionSettingsAlternateNicknames"]];
- if ([dict objectForKey:@"kTRConnectionSettingsNicknamePassword"]) [self setNicknamePassword:[dict objectForKey:@"kTRConnectionSettingsNicknamePassword"]];
- if ([dict objectForKey:@"kTRConnectionSettingsUsername"]) [self setUsername:[dict objectForKey:@"kTRConnectionSettingsUsername"]];
- if ([dict objectForKey:@"kTRConnectionSettingsPassword"]) [self setPassword:[dict objectForKey:@"kTRConnectionSettingsPassword"]];
- if ([dict objectForKey:@"kTRConnectionSettingsRealname"]) [self setRealname:[dict objectForKey:@"kTRConnectionSettingsRealname"]];
- if ([dict objectForKey:@"kTRConnectionSettingsDelegate"]) [self setDelegate:[dict objectForKey:@"kTRConnectionSettingsDelegate"]];
- return self;
- }
- + (id)connection {
- return [[[TRConnection alloc] init] autorelease];
- }
- + (id)connectionWithDictionary:(NSDictionary*)dict {
- return [[[TRConnection alloc] initWithDictionary:dict] autorelease];
- }
- #pragma mark Getting
- - (TRConnectionStatus)status {
- return _status;
- }
- - (NSString*)server {
- return _server;
- }
- - (UInt16)port {
- return _port;
- }
- - (NSString*)preferredNickname {
- return _preferredNickname;
- }
- - (NSString*)nickname {
- return _nickname;
- }
- - (NSArray*)alternateNicknames {
- return _alternateNicknames;
- }
- - (NSString*)nicknamePassword {
- return _nicknamePassword;
- }
- - (NSString*)username {
- return _username;
- }
- - (NSString*)password {
- return _password;
- }
- - (NSString*)realname {
- return _realname;
- }
- - (NSStringEncoding)encoding {
- return _encoding;
- }
- - (TRUser*)localUser {
- return _localUser;
- }
- - (id)delegate {
- return _delegate;
- }
- #pragma mark Setting
- - (void)setServer:(NSString*)server {
- TRSafeCopyAssign(&_server, server);
- }
- - (void)setPort:(UInt16)port {
- _port = port;
- }
- - (void)setNickname:(NSString*)nickname {
- TRSafeCopyAssign(&_preferredNickname, nickname);
- if (_status != TRConnectionConnectedStatus && _status != TRConnectionRegisteredStatus) {
- TRSafeCopyAssign(&_nickname, nickname);
- } else {
- // try to set nickname here.
- }
- }
- - (void)setAlternateNicknames:(NSArray*)alternateNicknames {
- TRSafeCopyAssign(&_alternateNicknames, alternateNicknames);
- }
- - (void)setNicknamePassword:(NSString*)nicknamePassword {
- TRSafeCopyAssign(&_nicknamePassword, nicknamePassword);
- }
- - (void)setUsername:(NSString*)username {
- TRSafeCopyAssign(&_username, username);
- }
- - (void)setPassword:(NSString*)password {
- TRSafeCopyAssign(&_password, password);
- }
- - (void)setRealname:(NSString*)realname {
- TRSafeCopyAssign(&_realname, realname);
- }
- - (void)setEncoding:(NSStringEncoding)encoding {
- _encoding = encoding;
- }
- - (void)setDelegate:(id)delegate {
- _delegate = delegate;
- }
- #pragma mark Connecting & Disconnecting
- - (void)connect {
- if (_status != TRConnectionDisconnectedStatus && _status != TRConnectionServerDisconnectedStatus && _status != TRConnectionSuspendedStatus) return;
- //[self _setStatus:TRConnectionConnectingStatus];
- _status = TRConnectionConnectingStatus;
- if ([_delegate respondsToSelector:@selector(connectionWillConnect:)])
- [_delegate connectionWillConnect:self];
- [NSThread detachNewThreadSelector:@selector(_runLoop) toTarget:self withObject:nil];
- [_threadWaitLock lockWhenCondition:1];
- [_threadWaitLock unlockWithCondition:0];
- _sendQueueProcessing = NO;
- if (_connectionThread)
- [self performSelector:@selector(_connect) inThread:_connectionThread];
- }
- - (void)disconnect {
- }
- #pragma mark Sending
- - (void)sendRawMessage:(id)raw {
- [self sendRawMessage:raw immediately:NO];
- }
- - (void)sendRawMessage:(id)raw immediately:(BOOL)now {
- if (_status != TRConnectionConnectedStatus) return;
- NSParameterAssert(raw != nil);
- NSParameterAssert([raw isKindOfClass:[NSData class]] || [raw isKindOfClass:[NSString class]]);
- if (now) {
- [self performSelector:@selector(_writeDataToServer:) withObject:raw inThread:_connectionThread];
- } else {
- if (!_sendQueue) _sendQueue = [[NSMutableArray allocWithZone:nil] initWithCapacity:20];
- @synchronized (_sendQueue) {
- [_sendQueue addObject:raw];
- }
- if (!_sendQueueProcessing && _connectionThread)
- [self performSelector:@selector(_startSendQueue) withObject:nil inThread:_connectionThread];
- }
- }
- - (void)sendRawMessageWithFormat:(NSString*)format, ... {
- NSParameterAssert(format != nil);
- va_list ap;
- va_start(ap, format);
- NSString *command = [[NSString allocWithZone:nil] initWithFormat:format arguments:ap];
- va_end(ap);
- [self sendRawMessage:command immediately:NO];
- [command release];
- }
- - (void)sendRawMessageImmediatelyWithFormat:(NSString*)format, ... {
- NSParameterAssert( format != nil );
- va_list ap;
- va_start( ap, format );
- NSString *command = [[NSString allocWithZone:nil] initWithFormat:format arguments:ap];
- va_end( ap );
- [self sendRawMessage:command immediately:YES];
- [command release];
- }
- - (void)sendRawMessageWithComponents:(id)firstComponent, ... {
- NSParameterAssert(firstComponent != nil);
- NSMutableData *data = [[NSMutableData allocWithZone:nil] initWithCapacity:512];
- id object = firstComponent;
- va_list ap;
- va_start(ap, firstComponent);
- do {
- if ([object isKindOfClass:[NSData class]]) {
- [data appendData:object];
- } else if ([firstComponent isKindOfClass:[NSString class]]) {
- NSData *stringData = [object dataUsingEncoding:[self encoding] allowLossyConversion:YES];
- [data appendData:stringData];
- } else {
- NSData *stringData = [[object description] dataUsingEncoding:[self encoding] allowLossyConversion:YES];
- [data appendData:stringData];
- }
- } while ((object = va_arg(ap, void*)));
- va_end(ap);
- [self sendRawMessage:data immediately:NO];
- [data release];
- }
- - (void)sendRawMessageImmediatelyWithComponents:(id)firstComponent, ... {
- NSParameterAssert(firstComponent != nil);
- NSMutableData *data = [[NSMutableData allocWithZone:nil] initWithCapacity:512];
- id object = firstComponent;
- va_list ap;
- va_start(ap, firstComponent);
- do {
- if ([object isKindOfClass:[NSData class]]) {
- [data appendData:object];
- } else if ([firstComponent isKindOfClass:[NSString class]]) {
- NSData *stringData = [object dataUsingEncoding:[self encoding] allowLossyConversion:YES];
- [data appendData:stringData];
- } else {
- NSData *stringData = [[object description] dataUsingEncoding:[self encoding] allowLossyConversion:YES];
- [data appendData:stringData];
- }
- } while ((object = va_arg(ap, void*)));
- va_end(ap);
- [self sendRawMessage:data immediately:YES];
- [data release];
- }
- - (void)sendPacket:(TRPacket*)packet {
- [self sendRawMessage:[packet data]];
- }
- - (void)sendPacket:(TRPacket*)packet immediately:(BOOL)now {
- [self sendRawMessage:packet immediately:now];
- }
- #pragma mark Users
- - (NSSet*)knownUsers {
- return [NSSet setWithArray:[_knownUsers allValues]];
- }
- - (TRUser*)userWithIdentifier:(NSString*)identifier {
- NSString *ident = [identifier lowercaseString];
- if ([ident isEqualToString:[[self localUser] identifier]]) return [self localUser];
- if (!_knownUsers) _knownUsers = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:100];
- TRUser *user = nil;
- @synchronized(_knownUsers) {
- user = [_knownUsers objectForKey:ident];
- if (user) return user;
- user = [[TRUser allocWithZone:nil] init];
- [user setConnection:self];
- [user setNickname:identifier];
- if (user) [_knownUsers setObject:user forKey:ident];
- }
- return [user autorelease];
- }
- - (void)updateUserInPacket:(TRPacket*)packet {
- if (![packet name] || ![[packet name] length]) {
- TRUser *user = [[TRUser allocWithZone:nil] init];
- [user setConnection:self];
- [user setNickname:[self server]];
- [packet setUser:[user autorelease]];
- return;
- }
- NSString *ident = [[packet name] lowercaseString];
- TRUser *user;
- if ([ident isEqualToString:[[self localUser] identifier]]) user = [self localUser];
- else {
- @synchronized(_knownUsers) {
- user = [_knownUsers objectForKey:ident];
- if (!user) {
- user = [[TRUser allocWithZone:nil] init];
- [user setConnection:self];
- [user setNickname:[packet name]];
- }
- }
- }
- if ((![user username] || ![[user username] length]) && ([packet username] && [[packet username] length])) {
- [user setUsername:[packet username]];
- }
- if ((![user hostname] || ![[user hostname] length]) && ([packet host] && [[packet host] length])) {
- [user setHostname:[packet host]];
- }
- [packet setUser:user];
- }
- @end
- #pragma mark Private Communication Methods
- @implementation TRConnection (TRConnectionCommunicationMethods)
- - (void)_runLoop {
- NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:nil] init];
- [_threadWaitLock lockWhenCondition:0];
- _connectionThread = [NSThread currentThread];
- [NSThread prepareForInterThreadMessages];
- [_threadWaitLock unlockWithCondition:1];
- if ([pool respondsToSelector:@selector(drain)])
- [pool drain];
- else
- [pool release];
- pool = nil;
- while (_status == TRConnectionConnectedStatus || _status == TRConnectionConnectingStatus || _status == TRConnectionRegisteredStatus) {
- pool = [[NSAutoreleasePool allocWithZone:nil] init];
- [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10.]];
- if ([pool respondsToSelector:@selector(drain)]) [pool drain];
- else [pool release];
- }
- pool = [[NSAutoreleasePool allocWithZone:nil] init];
- [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.]];
- if ([NSThread currentThread] == _connectionThread) _connectionThread = nil;
- if ([pool respondsToSelector:@selector(drain)]) [pool drain];
- else [pool release];
- }
- - (void)_connect {
- TRAssertCorrectThreadRequired(_connectionThread);
- id old = _socket;
- _socket = [[AsyncSocket allocWithZone:nil] initWithDelegate:self];
- [old setDelegate:nil];
- [old disconnect];
- [old release];
- if (![_socket connectToHost:[self server] onPort:[self port] error:NULL]) {
- // didnotconnect-shit
- }
- }
- - (void)_setStatus:(TRConnectionStatus)status {
- _status = status;
- }
- - (void)_writeDataToServer:(id)raw {
- TRAssertCorrectThreadRequired(_connectionThread);
- NSMutableData *data = nil;
- NSString *string = nil;
- if ([raw isKindOfClass:[NSMutableData class]]) {
- data = [raw retain];
- string = [[NSString allocWithZone:nil] initWithData:data encoding:[self encoding]];
- } else if ([raw isKindOfClass:[NSData class]]) {
- data = [raw mutableCopyWithZone:nil];
- string = [[NSString allocWithZone:nil] initWithData:data encoding:[self encoding]];
- } else if ([raw isKindOfClass:[NSString class]]) {
- data = [[raw dataUsingEncoding:[self encoding] allowLossyConversion:YES] mutableCopyWithZone:nil];
- string = [raw retain];
- }
- if ([data length] > 510) [data setLength:510];
- [data appendBytes:"\x0D\x0A" length:2];
- [_socket writeData:data withTimeout:-1. tag:0];
- [string release];
- [data release];
- }
- - (void)_startSendQueue {
- TRAssertCorrectThreadRequired(_connectionThread);
- if (_sendQueueProcessing) return;
- _sendQueueProcessing = YES;
- [self performSelector:@selector(_sendQueue) withObject:nil afterDelay:0.2];
- }
- - (void)_stopSendQueue {
- TRAssertCorrectThreadRequired(_connectionThread);
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_sendQueue) object:nil];
- _sendQueueProcessing = NO;
- }
- - (void)_sendQueue {
- TRAssertCorrectThreadRequired(_connectionThread);
- @synchronized(_sendQueue) {
- if (![_sendQueue count]) {
- _sendQueueProcessing = NO;
- return;
- }
- }
- NSData *data = nil;
- @synchronized(_sendQueue) {
- data = [[_sendQueue objectAtIndex:0] retain];
- [_sendQueue removeObjectAtIndex:0];
- if ([_sendQueue count])
- [self performSelector:@selector(_sendQueue) withObject:nil afterDelay:(0.2 + ([_sendQueue count] * 0.01))];
- else
- _sendQueueProcessing = NO;
- }
- [self _writeDataToServer:data];
- [data release];
- }
- - (void)_readNextMessageFromServer {
- TRAssertCorrectThreadRequired(_connectionThread);
- static NSData *delim = nil;
- if (!delim) delim = [[NSData allocWithZone:nil] initWithBytes:"\x0A" length:1];
- [_socket readDataToData:delim withTimeout:-1. tag:0];
- }
- @end
- #pragma mark IRC & Socket Handlers
- @implementation TRConnection (TRConnectionIRCAndSocketHandlers)
- #pragma mark Socket Delegates
- - (BOOL)socketWillConnect:(AsyncSocket*)socket {
- TRAssertCorrectThreadRequired(_connectionThread);
- // Do.. something!
- return YES;
- }
- - (void)socket:(AsyncSocket*)socket didConnectToHost:(NSString*)host port:(UInt16)port {
- TRAssertCorrectThreadRequired(_connectionThread);
- [self _setStatus:TRConnectionConnectedStatus];
- if ([_delegate respondsToSelector:@selector(connectionDidConnect:)])
- [_delegate performSelectorOnMainThread:@selector(connectionDidConnect:) withObject:self waitUntilDone:NO];
- [self sendRawMessageImmediatelyWithFormat:@"NICK %@", [self preferredNickname]];
- [self sendRawMessageImmediatelyWithFormat:@"USER %@ 0 * :%@",
- ([[self username] length] ? [self username] : @"anonymous"),
- ([[self realname] length] ? [self realname] : @"anonymous")];
- // init local user here.
- [self _readNextMessageFromServer];
- }
- - (void)socket:(AsyncSocket*)socket willDisconnectWithError:(NSError*)error {
- TRAssertCorrectThreadRequired(_connectionThread);
- NSLog(@"Connection Error: %@", error);
- }
- - (void)socketDidDisconnect:(AsyncSocket*)socket {
- TRAssertCorrectThreadRequired(_connectionThread);
- if (socket != _socket) return;
- NSLog(@"disconnected!");
- // cleanup..
- }
- - (void)socket:(AsyncSocket*)socket didReadData:(NSData*)data withTag:(long)tag {
- TRAssertCorrectThreadRequired(_connectionThread);
- TRPacket *packet = [TRPacket packetWithData:data];
- NSString *selectorString = [[NSString allocWithZone:nil] initWithFormat:@"_%@Packet:", [[packet command] lowercaseString]];
- SEL selector = NSSelectorFromString(selectorString);
- [selectorString release];
- [self updateUserInPacket:packet];
- if ([self respondsToSelector:selector]) {
- [self performSelector:selector withObject:packet];
- } else {
- [self performSelector:@selector(_defaultPacket:) withObject:packet];
- }
- [self _readNextMessageFromServer];
- }
- #pragma mark IRC Packet Handlers
- // Numbered packet handlers
- - (void)_001Packet:(TRPacket*)packet {
- TRAssertCorrectThreadRequired(_connectionThread);
- if (_localUser) [_localUser release];
- _localUser = [[TRUser alloc] init];
- [_localUser setNickname:_nickname];
- [self _setStatus:TRConnectionRegisteredStatus];
- if ([_delegate respondsToSelector:@selector(connectionDidRegister:)])
- [_delegate performSelectorOnMainThread:@selector(connectionDidRegister:) withObject:self waitUntilDone:NO];
- if ([[self nicknamePassword] length])
- [self sendRawMessageImmediatelyWithFormat:@"NickServ IDENTIFY %@", [self nicknamePassword]];
- }
- // String-command packet handlers
- - (void)_noticePacket:(TRPacket*)packet {
- NSLog(@"NOTICE (%@): %@", [[packet user] nickname], [packet messageStringWithEncoding:NSASCIIStringEncoding]);
- }
- // --------------------------------------------------
- - (void)_defaultPacket:(TRPacket*)packet {
- TRAssertCorrectThreadRequired(_connectionThread);
- NSLog(@"Unhandled packet (%@): %@", [packet command], [[[NSString alloc] initWithData:[packet rawData] encoding:NSUTF8StringEncoding] autorelease]);
- //[packet debug];
- }
- @end
Add Comment
Please, Sign In to add comment