Guest User

Untitled

a guest
Jan 13th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.37 KB | None | 0 0
  1. #import <Foundation/Foundation.h>
  2. #import "TRPacket.h"
  3. #import "TRUtilities.h"
  4. #import "TRConnection.h"
  5.  
  6. const NSString *kTRConnectionSettingsServer = @"kTRConnectionSettingsServer";
  7. const NSString *kTRConnectionSettingsPort = @"kTRConnectionSettingsPort";
  8. const NSString *kTRConnectionSettingsNickname = @"kTRConnectionSettingsNickname";
  9. const NSString *kTRConnectionSettingsAlternateNicknames = @"kTRConnectionSettingsAlternateNicknames";
  10. const NSString *kTRConnectionSettingsNicknamePassword = @"kTRConnectionSettingsNicknamePassword";
  11. const NSString *kTRConnectionSettingsUsername = @"kTRConnectionSettingsUsername";
  12. const NSString *kTRConnectionSettingsPassword = @"kTRConnectionSettingsPassword";
  13. const NSString *kTRConnectionSettingsRealname = @"kTRConnectionSettingsRealname";
  14. const NSString *kTRConnectionSettingsDelegate = @"kTRConnectionSettingsDelegate";
  15.  
  16. @implementation TRConnection
  17.  
  18. #pragma mark Initializing
  19.  
  20. - (id)init {
  21. if (!(self = [super init])) return nil;
  22. _threadWaitLock = [[NSConditionLock allocWithZone:nil] initWithCondition:0];
  23. _status = TRConnectionDisconnectedStatus;
  24. _encoding = NSUTF8StringEncoding;
  25. [self setServer:@"irc.freenode.net"];
  26. [self setPort:6667];
  27. [self setNickname:@"TribUser"];
  28. [self setAlternateNicknames:[NSArray arrayWithObjects:@"TribUser_", @"TribUser__", nil]];
  29. [self setUsername:@"TribUser"];
  30. [self setRealname:@"Tribunal User"];
  31. return self;
  32. }
  33.  
  34. - (id)initWithDictionary:(NSDictionary*)dict {
  35. if (!(self = [self init])) return nil;
  36. if ([dict objectForKey:@"kTRConnectionSettingsServer"]) [self setServer:[dict objectForKey:@"kTRConnectionSettingsServer"]];
  37. if ([dict objectForKey:@"kTRConnectionSettingsPort"]) [self setPort:[[dict objectForKey:@"kTRConnectionSettingsPort"] intValue]];
  38. if ([dict objectForKey:@"kTRConnectionSettingsNickname"]) [self setNickname:[dict objectForKey:@"kTRConnectionSettingsNickname"]];
  39. if ([dict objectForKey:@"kTRConnectionSettingsAlternateNicknames"]) [self setAlternateNicknames:[dict objectForKey:@"kTRConnectionSettingsAlternateNicknames"]];
  40. if ([dict objectForKey:@"kTRConnectionSettingsNicknamePassword"]) [self setNicknamePassword:[dict objectForKey:@"kTRConnectionSettingsNicknamePassword"]];
  41. if ([dict objectForKey:@"kTRConnectionSettingsUsername"]) [self setUsername:[dict objectForKey:@"kTRConnectionSettingsUsername"]];
  42. if ([dict objectForKey:@"kTRConnectionSettingsPassword"]) [self setPassword:[dict objectForKey:@"kTRConnectionSettingsPassword"]];
  43. if ([dict objectForKey:@"kTRConnectionSettingsRealname"]) [self setRealname:[dict objectForKey:@"kTRConnectionSettingsRealname"]];
  44. if ([dict objectForKey:@"kTRConnectionSettingsDelegate"]) [self setDelegate:[dict objectForKey:@"kTRConnectionSettingsDelegate"]];
  45. return self;
  46. }
  47.  
  48. + (id)connection {
  49. return [[[TRConnection alloc] init] autorelease];
  50. }
  51.  
  52. + (id)connectionWithDictionary:(NSDictionary*)dict {
  53. return [[[TRConnection alloc] initWithDictionary:dict] autorelease];
  54. }
  55.  
  56. #pragma mark Getting
  57.  
  58. - (TRConnectionStatus)status {
  59. return _status;
  60. }
  61.  
  62. - (NSString*)server {
  63. return _server;
  64. }
  65.  
  66. - (UInt16)port {
  67. return _port;
  68. }
  69.  
  70. - (NSString*)preferredNickname {
  71. return _preferredNickname;
  72. }
  73.  
  74. - (NSString*)nickname {
  75. return _nickname;
  76. }
  77.  
  78. - (NSArray*)alternateNicknames {
  79. return _alternateNicknames;
  80. }
  81.  
  82. - (NSString*)nicknamePassword {
  83. return _nicknamePassword;
  84. }
  85.  
  86. - (NSString*)username {
  87. return _username;
  88. }
  89.  
  90. - (NSString*)password {
  91. return _password;
  92. }
  93.  
  94. - (NSString*)realname {
  95. return _realname;
  96. }
  97.  
  98. - (NSStringEncoding)encoding {
  99. return _encoding;
  100. }
  101.  
  102. - (TRUser*)localUser {
  103. return _localUser;
  104. }
  105.  
  106. - (id)delegate {
  107. return _delegate;
  108. }
  109.  
  110. #pragma mark Setting
  111.  
  112. - (void)setServer:(NSString*)server {
  113. TRSafeCopyAssign(&_server, server);
  114. }
  115.  
  116. - (void)setPort:(UInt16)port {
  117. _port = port;
  118. }
  119.  
  120. - (void)setNickname:(NSString*)nickname {
  121. TRSafeCopyAssign(&_preferredNickname, nickname);
  122. if (_status != TRConnectionConnectedStatus && _status != TRConnectionRegisteredStatus) {
  123. TRSafeCopyAssign(&_nickname, nickname);
  124. } else {
  125. // try to set nickname here.
  126. }
  127. }
  128.  
  129. - (void)setAlternateNicknames:(NSArray*)alternateNicknames {
  130. TRSafeCopyAssign(&_alternateNicknames, alternateNicknames);
  131. }
  132.  
  133. - (void)setNicknamePassword:(NSString*)nicknamePassword {
  134. TRSafeCopyAssign(&_nicknamePassword, nicknamePassword);
  135. }
  136.  
  137. - (void)setUsername:(NSString*)username {
  138. TRSafeCopyAssign(&_username, username);
  139. }
  140.  
  141. - (void)setPassword:(NSString*)password {
  142. TRSafeCopyAssign(&_password, password);
  143. }
  144.  
  145. - (void)setRealname:(NSString*)realname {
  146. TRSafeCopyAssign(&_realname, realname);
  147. }
  148.  
  149. - (void)setEncoding:(NSStringEncoding)encoding {
  150. _encoding = encoding;
  151. }
  152.  
  153. - (void)setDelegate:(id)delegate {
  154. _delegate = delegate;
  155. }
  156.  
  157. #pragma mark Connecting & Disconnecting
  158.  
  159. - (void)connect {
  160. if (_status != TRConnectionDisconnectedStatus && _status != TRConnectionServerDisconnectedStatus && _status != TRConnectionSuspendedStatus) return;
  161.  
  162. //[self _setStatus:TRConnectionConnectingStatus];
  163. _status = TRConnectionConnectingStatus;
  164.  
  165. if ([_delegate respondsToSelector:@selector(connectionWillConnect:)])
  166. [_delegate connectionWillConnect:self];
  167.  
  168. [NSThread detachNewThreadSelector:@selector(_runLoop) toTarget:self withObject:nil];
  169.  
  170. [_threadWaitLock lockWhenCondition:1];
  171. [_threadWaitLock unlockWithCondition:0];
  172. _sendQueueProcessing = NO;
  173.  
  174. if (_connectionThread)
  175. [self performSelector:@selector(_connect) inThread:_connectionThread];
  176. }
  177.  
  178. - (void)disconnect {
  179.  
  180. }
  181.  
  182. #pragma mark Sending
  183.  
  184. - (void)sendRawMessage:(id)raw {
  185. [self sendRawMessage:raw immediately:NO];
  186. }
  187.  
  188. - (void)sendRawMessage:(id)raw immediately:(BOOL)now {
  189. if (_status != TRConnectionConnectedStatus) return;
  190.  
  191. NSParameterAssert(raw != nil);
  192. NSParameterAssert([raw isKindOfClass:[NSData class]] || [raw isKindOfClass:[NSString class]]);
  193.  
  194. if (now) {
  195. [self performSelector:@selector(_writeDataToServer:) withObject:raw inThread:_connectionThread];
  196. } else {
  197. if (!_sendQueue) _sendQueue = [[NSMutableArray allocWithZone:nil] initWithCapacity:20];
  198. @synchronized (_sendQueue) {
  199. [_sendQueue addObject:raw];
  200. }
  201.  
  202. if (!_sendQueueProcessing && _connectionThread)
  203. [self performSelector:@selector(_startSendQueue) withObject:nil inThread:_connectionThread];
  204. }
  205. }
  206.  
  207. - (void)sendRawMessageWithFormat:(NSString*)format, ... {
  208. NSParameterAssert(format != nil);
  209.  
  210. va_list ap;
  211. va_start(ap, format);
  212.  
  213. NSString *command = [[NSString allocWithZone:nil] initWithFormat:format arguments:ap];
  214.  
  215. va_end(ap);
  216.  
  217. [self sendRawMessage:command immediately:NO];
  218. [command release];
  219. }
  220.  
  221. - (void)sendRawMessageImmediatelyWithFormat:(NSString*)format, ... {
  222. NSParameterAssert( format != nil );
  223.  
  224. va_list ap;
  225. va_start( ap, format );
  226.  
  227. NSString *command = [[NSString allocWithZone:nil] initWithFormat:format arguments:ap];
  228.  
  229. va_end( ap );
  230.  
  231. [self sendRawMessage:command immediately:YES];
  232. [command release];
  233. }
  234.  
  235. - (void)sendRawMessageWithComponents:(id)firstComponent, ... {
  236. NSParameterAssert(firstComponent != nil);
  237.  
  238. NSMutableData *data = [[NSMutableData allocWithZone:nil] initWithCapacity:512];
  239. id object = firstComponent;
  240.  
  241. va_list ap;
  242. va_start(ap, firstComponent);
  243.  
  244. do {
  245. if ([object isKindOfClass:[NSData class]]) {
  246. [data appendData:object];
  247. } else if ([firstComponent isKindOfClass:[NSString class]]) {
  248. NSData *stringData = [object dataUsingEncoding:[self encoding] allowLossyConversion:YES];
  249. [data appendData:stringData];
  250. } else {
  251. NSData *stringData = [[object description] dataUsingEncoding:[self encoding] allowLossyConversion:YES];
  252. [data appendData:stringData];
  253. }
  254. } while ((object = va_arg(ap, void*)));
  255.  
  256. va_end(ap);
  257.  
  258. [self sendRawMessage:data immediately:NO];
  259. [data release];
  260. }
  261.  
  262. - (void)sendRawMessageImmediatelyWithComponents:(id)firstComponent, ... {
  263. NSParameterAssert(firstComponent != nil);
  264.  
  265. NSMutableData *data = [[NSMutableData allocWithZone:nil] initWithCapacity:512];
  266. id object = firstComponent;
  267.  
  268. va_list ap;
  269. va_start(ap, firstComponent);
  270.  
  271. do {
  272. if ([object isKindOfClass:[NSData class]]) {
  273. [data appendData:object];
  274. } else if ([firstComponent isKindOfClass:[NSString class]]) {
  275. NSData *stringData = [object dataUsingEncoding:[self encoding] allowLossyConversion:YES];
  276. [data appendData:stringData];
  277. } else {
  278. NSData *stringData = [[object description] dataUsingEncoding:[self encoding] allowLossyConversion:YES];
  279. [data appendData:stringData];
  280. }
  281. } while ((object = va_arg(ap, void*)));
  282.  
  283. va_end(ap);
  284.  
  285. [self sendRawMessage:data immediately:YES];
  286. [data release];
  287. }
  288.  
  289. - (void)sendPacket:(TRPacket*)packet {
  290. [self sendRawMessage:[packet data]];
  291. }
  292.  
  293. - (void)sendPacket:(TRPacket*)packet immediately:(BOOL)now {
  294. [self sendRawMessage:packet immediately:now];
  295. }
  296.  
  297. #pragma mark Users
  298.  
  299. - (NSSet*)knownUsers {
  300. return [NSSet setWithArray:[_knownUsers allValues]];
  301. }
  302.  
  303. - (TRUser*)userWithIdentifier:(NSString*)identifier {
  304. NSString *ident = [identifier lowercaseString];
  305.  
  306. if ([ident isEqualToString:[[self localUser] identifier]]) return [self localUser];
  307.  
  308. if (!_knownUsers) _knownUsers = [[NSMutableDictionary allocWithZone:nil] initWithCapacity:100];
  309.  
  310. TRUser *user = nil;
  311. @synchronized(_knownUsers) {
  312. user = [_knownUsers objectForKey:ident];
  313. if (user) return user;
  314.  
  315. user = [[TRUser allocWithZone:nil] init];
  316. [user setConnection:self];
  317. [user setNickname:identifier];
  318. if (user) [_knownUsers setObject:user forKey:ident];
  319. }
  320.  
  321. return [user autorelease];
  322. }
  323.  
  324. - (void)updateUserInPacket:(TRPacket*)packet {
  325. if (![packet name] || ![[packet name] length]) {
  326. TRUser *user = [[TRUser allocWithZone:nil] init];
  327. [user setConnection:self];
  328. [user setNickname:[self server]];
  329. [packet setUser:[user autorelease]];
  330. return;
  331. }
  332.  
  333. NSString *ident = [[packet name] lowercaseString];
  334. TRUser *user;
  335.  
  336. if ([ident isEqualToString:[[self localUser] identifier]]) user = [self localUser];
  337. else {
  338. @synchronized(_knownUsers) {
  339. user = [_knownUsers objectForKey:ident];
  340. if (!user) {
  341. user = [[TRUser allocWithZone:nil] init];
  342. [user setConnection:self];
  343. [user setNickname:[packet name]];
  344. }
  345. }
  346. }
  347.  
  348. if ((![user username] || ![[user username] length]) && ([packet username] && [[packet username] length])) {
  349. [user setUsername:[packet username]];
  350. }
  351. if ((![user hostname] || ![[user hostname] length]) && ([packet host] && [[packet host] length])) {
  352. [user setHostname:[packet host]];
  353. }
  354.  
  355. [packet setUser:user];
  356. }
  357.  
  358. @end
  359.  
  360. #pragma mark Private Communication Methods
  361.  
  362. @implementation TRConnection (TRConnectionCommunicationMethods)
  363.  
  364. - (void)_runLoop {
  365. NSAutoreleasePool *pool = [[NSAutoreleasePool allocWithZone:nil] init];
  366.  
  367. [_threadWaitLock lockWhenCondition:0];
  368.  
  369. _connectionThread = [NSThread currentThread];
  370. [NSThread prepareForInterThreadMessages];
  371.  
  372. [_threadWaitLock unlockWithCondition:1];
  373.  
  374. if ([pool respondsToSelector:@selector(drain)])
  375. [pool drain];
  376. else
  377. [pool release];
  378. pool = nil;
  379.  
  380. while (_status == TRConnectionConnectedStatus || _status == TRConnectionConnectingStatus || _status == TRConnectionRegisteredStatus) {
  381. pool = [[NSAutoreleasePool allocWithZone:nil] init];
  382. [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10.]];
  383. if ([pool respondsToSelector:@selector(drain)]) [pool drain];
  384. else [pool release];
  385. }
  386.  
  387. pool = [[NSAutoreleasePool allocWithZone:nil] init];
  388.  
  389. [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.]];
  390.  
  391. if ([NSThread currentThread] == _connectionThread) _connectionThread = nil;
  392.  
  393. if ([pool respondsToSelector:@selector(drain)]) [pool drain];
  394. else [pool release];
  395. }
  396.  
  397. - (void)_connect {
  398. TRAssertCorrectThreadRequired(_connectionThread);
  399.  
  400. id old = _socket;
  401. _socket = [[AsyncSocket allocWithZone:nil] initWithDelegate:self];
  402. [old setDelegate:nil];
  403. [old disconnect];
  404. [old release];
  405.  
  406. if (![_socket connectToHost:[self server] onPort:[self port] error:NULL]) {
  407. // didnotconnect-shit
  408. }
  409. }
  410.  
  411. - (void)_setStatus:(TRConnectionStatus)status {
  412. _status = status;
  413. }
  414.  
  415. - (void)_writeDataToServer:(id)raw {
  416. TRAssertCorrectThreadRequired(_connectionThread);
  417.  
  418. NSMutableData *data = nil;
  419. NSString *string = nil;
  420.  
  421. if ([raw isKindOfClass:[NSMutableData class]]) {
  422. data = [raw retain];
  423. string = [[NSString allocWithZone:nil] initWithData:data encoding:[self encoding]];
  424. } else if ([raw isKindOfClass:[NSData class]]) {
  425. data = [raw mutableCopyWithZone:nil];
  426. string = [[NSString allocWithZone:nil] initWithData:data encoding:[self encoding]];
  427. } else if ([raw isKindOfClass:[NSString class]]) {
  428. data = [[raw dataUsingEncoding:[self encoding] allowLossyConversion:YES] mutableCopyWithZone:nil];
  429. string = [raw retain];
  430. }
  431.  
  432. if ([data length] > 510) [data setLength:510];
  433. [data appendBytes:"\x0D\x0A" length:2];
  434.  
  435. [_socket writeData:data withTimeout:-1. tag:0];
  436.  
  437. [string release];
  438. [data release];
  439. }
  440.  
  441. - (void)_startSendQueue {
  442. TRAssertCorrectThreadRequired(_connectionThread);
  443.  
  444. if (_sendQueueProcessing) return;
  445. _sendQueueProcessing = YES;
  446.  
  447. [self performSelector:@selector(_sendQueue) withObject:nil afterDelay:0.2];
  448. }
  449.  
  450. - (void)_stopSendQueue {
  451. TRAssertCorrectThreadRequired(_connectionThread);
  452.  
  453. [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_sendQueue) object:nil];
  454. _sendQueueProcessing = NO;
  455. }
  456.  
  457. - (void)_sendQueue {
  458. TRAssertCorrectThreadRequired(_connectionThread);
  459.  
  460. @synchronized(_sendQueue) {
  461. if (![_sendQueue count]) {
  462. _sendQueueProcessing = NO;
  463. return;
  464. }
  465. }
  466.  
  467. NSData *data = nil;
  468. @synchronized(_sendQueue) {
  469. data = [[_sendQueue objectAtIndex:0] retain];
  470. [_sendQueue removeObjectAtIndex:0];
  471.  
  472. if ([_sendQueue count])
  473. [self performSelector:@selector(_sendQueue) withObject:nil afterDelay:(0.2 + ([_sendQueue count] * 0.01))];
  474. else
  475. _sendQueueProcessing = NO;
  476. }
  477.  
  478. [self _writeDataToServer:data];
  479. [data release];
  480. }
  481.  
  482. - (void)_readNextMessageFromServer {
  483. TRAssertCorrectThreadRequired(_connectionThread);
  484.  
  485. static NSData *delim = nil;
  486. if (!delim) delim = [[NSData allocWithZone:nil] initWithBytes:"\x0A" length:1];
  487. [_socket readDataToData:delim withTimeout:-1. tag:0];
  488. }
  489.  
  490. @end
  491.  
  492. #pragma mark IRC & Socket Handlers
  493.  
  494. @implementation TRConnection (TRConnectionIRCAndSocketHandlers)
  495.  
  496. #pragma mark Socket Delegates
  497.  
  498. - (BOOL)socketWillConnect:(AsyncSocket*)socket {
  499. TRAssertCorrectThreadRequired(_connectionThread);
  500. // Do.. something!
  501. return YES;
  502. }
  503.  
  504. - (void)socket:(AsyncSocket*)socket didConnectToHost:(NSString*)host port:(UInt16)port {
  505. TRAssertCorrectThreadRequired(_connectionThread);
  506.  
  507. [self _setStatus:TRConnectionConnectedStatus];
  508.  
  509. if ([_delegate respondsToSelector:@selector(connectionDidConnect:)])
  510. [_delegate performSelectorOnMainThread:@selector(connectionDidConnect:) withObject:self waitUntilDone:NO];
  511.  
  512. [self sendRawMessageImmediatelyWithFormat:@"NICK %@", [self preferredNickname]];
  513. [self sendRawMessageImmediatelyWithFormat:@"USER %@ 0 * :%@",
  514. ([[self username] length] ? [self username] : @"anonymous"),
  515. ([[self realname] length] ? [self realname] : @"anonymous")];
  516.  
  517. // init local user here.
  518.  
  519. [self _readNextMessageFromServer];
  520. }
  521.  
  522. - (void)socket:(AsyncSocket*)socket willDisconnectWithError:(NSError*)error {
  523. TRAssertCorrectThreadRequired(_connectionThread);
  524. NSLog(@"Connection Error: %@", error);
  525. }
  526.  
  527. - (void)socketDidDisconnect:(AsyncSocket*)socket {
  528. TRAssertCorrectThreadRequired(_connectionThread);
  529. if (socket != _socket) return;
  530.  
  531. NSLog(@"disconnected!");
  532.  
  533. // cleanup..
  534. }
  535.  
  536. - (void)socket:(AsyncSocket*)socket didReadData:(NSData*)data withTag:(long)tag {
  537. TRAssertCorrectThreadRequired(_connectionThread);
  538.  
  539. TRPacket *packet = [TRPacket packetWithData:data];
  540. NSString *selectorString = [[NSString allocWithZone:nil] initWithFormat:@"_%@Packet:", [[packet command] lowercaseString]];
  541. SEL selector = NSSelectorFromString(selectorString);
  542. [selectorString release];
  543.  
  544. [self updateUserInPacket:packet];
  545.  
  546. if ([self respondsToSelector:selector]) {
  547. [self performSelector:selector withObject:packet];
  548. } else {
  549. [self performSelector:@selector(_defaultPacket:) withObject:packet];
  550. }
  551.  
  552. [self _readNextMessageFromServer];
  553. }
  554.  
  555. #pragma mark IRC Packet Handlers
  556.  
  557. // Numbered packet handlers
  558.  
  559. - (void)_001Packet:(TRPacket*)packet {
  560. TRAssertCorrectThreadRequired(_connectionThread);
  561.  
  562. if (_localUser) [_localUser release];
  563. _localUser = [[TRUser alloc] init];
  564. [_localUser setNickname:_nickname];
  565.  
  566. [self _setStatus:TRConnectionRegisteredStatus];
  567.  
  568. if ([_delegate respondsToSelector:@selector(connectionDidRegister:)])
  569. [_delegate performSelectorOnMainThread:@selector(connectionDidRegister:) withObject:self waitUntilDone:NO];
  570.  
  571. if ([[self nicknamePassword] length])
  572. [self sendRawMessageImmediatelyWithFormat:@"NickServ IDENTIFY %@", [self nicknamePassword]];
  573. }
  574.  
  575. // String-command packet handlers
  576.  
  577. - (void)_noticePacket:(TRPacket*)packet {
  578. NSLog(@"NOTICE (%@): %@", [[packet user] nickname], [packet messageStringWithEncoding:NSASCIIStringEncoding]);
  579. }
  580.  
  581. // --------------------------------------------------
  582.  
  583. - (void)_defaultPacket:(TRPacket*)packet {
  584. TRAssertCorrectThreadRequired(_connectionThread);
  585. NSLog(@"Unhandled packet (%@): %@", [packet command], [[[NSString alloc] initWithData:[packet rawData] encoding:NSUTF8StringEncoding] autorelease]);
  586. //[packet debug];
  587. }
  588.  
  589. @end
Add Comment
Please, Sign In to add comment