PageRenderTime 58ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/lilypad/Sources/LPAccount.m

https://github.com/sapo/sapo-messenger-for-mac
Objective C | 1713 lines | 1205 code | 398 blank | 110 comment | 165 complexity | 2ca032a040c5967696f8219451fa19e2 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. //
  2. // LPAccount.m
  3. // Lilypad
  4. //
  5. // Copyright (C) 2006-2008 PT.COM, All rights reserved.
  6. // Authors: Joao Pavao <jpavao@co.sapo.pt>
  7. // Jason Kim <jason@512k.org>
  8. //
  9. // For more information on licensing, read the README file.
  10. // Para mais informações sobre o licenciamento, leia o ficheiro README.
  11. //
  12. #import "LPAccount.h"
  13. #import "LPChat.h"
  14. #import "LPChatsManager.h"
  15. #import "LPGroupChat.h"
  16. #import "LPRoster.h"
  17. #import "LPContact.h"
  18. #import "LPContactEntry.h"
  19. #import "LPFileTransfer.h"
  20. #import "LPServerItemsInfo.h"
  21. #import "LPSapoAgents.h"
  22. #import "LFAppController.h"
  23. #import "LFPlatformBridge.h"
  24. #import "LPKeychainManager.h"
  25. #import "LPPubManager.h"
  26. #import <AddressBook/AddressBook.h>
  27. #import <SystemConfiguration/SystemConfiguration.h>
  28. #import <netinet/in.h>
  29. #import <arpa/inet.h>
  30. #ifndef REACHABILITY_DEBUG
  31. #define REACHABILITY_DEBUG (BOOL)0
  32. #endif
  33. @interface LPAccount () // Private Methods
  34. - (NSString *)p_computerNameForLocation;
  35. - (void)p_updateLocationFromChangedComputerName;
  36. // The actual accessors for these two attributes
  37. - (void)p_setStatus:(LPStatus)theStatus;
  38. - (void)p_setStatusMessage:(NSString *)theStatus;
  39. - (NSString *)p_statusMessage;
  40. - (void)p_setTargetStatus:(LPStatus)theStatus;
  41. - (void)p_setOnlineStatus:(LPStatus)theStatus message:(NSString *)theMessage saveToServer:(BOOL)saveFlag;
  42. - (void)p_setOnlineStatus:(LPStatus)theStatus message:(NSString *)theMessage saveToServer:(BOOL)saveFlag alsoSaveStatusMessage:(BOOL)saveMsg;
  43. - (void)p_setAutomaticReconnectionStatus:(LPAutoReconnectStatus)status;
  44. - (void)p_setAvatar:(NSImage *)avatar;
  45. - (void)p_changeAndAnnounceAvatar:(NSImage *)avatar;
  46. - (void)p_setSMSCredit:(int)credit freeMessages:(int)freeMsgs totalSent:(int)totalSent;
  47. - (NSString *)p_lastAttemptedServerHost;
  48. - (void)p_setLastAttemptedServerHost:(NSString *)host;
  49. - (BOOL)p_lastConnectionAttemptDidFail;
  50. - (void)p_setLastConnectionAttemptDidFail:(BOOL)flag;
  51. @end
  52. #pragma mark -
  53. #pragma mark LPAccountAutomaticReconnectionContext
  54. @interface LPAccountAutomaticReconnectionContext : NSObject
  55. {
  56. SCNetworkReachabilityRef m_serverHostReachabilityRef;
  57. LPAccount *m_account;
  58. NSString *m_observedLocalAddress;
  59. NSString *m_observedRemoteAddress;
  60. LPAutoReconnectStatus m_autoReconnectStatus;
  61. SCNetworkConnectionFlags m_lastNetworkConnectionFlags;
  62. LPStatus m_lastOnlineStatus;
  63. NSString *m_lastOnlineStatusMessage;
  64. NSTimer *m_lastScheduledReconnectionTimer;
  65. NSTimer *m_connectionTimeoutTimer;
  66. }
  67. - initForObservingConnectionWithLocalAddress:(NSString *)localAddress remoteAddress:(NSString *)remoteAddress account:(LPAccount *)account;
  68. - (LPAccount *)account;
  69. - (NSString *)observedConnectionLocalAddress;
  70. - (NSString *)observedConnectionRemoteAddress;
  71. - (void)setObservedConnectionWithLocalAddress:(NSString *)localAddress remoteAddress:(NSString *)remoteAddress;
  72. - (BOOL)isInTheMidstOfAutomaticReconnection;
  73. - (LPAutoReconnectStatus)automaticReconnectionStatus;
  74. - (SCNetworkConnectionFlags)lastNetworkConnectionFlags;
  75. - (void)setLastNetworkConnectionFlags:(SCNetworkConnectionFlags)flags;
  76. - (void)cancelAllTimers;
  77. - (void)handleNetworkInterfaceDown;
  78. - (void)handleNetworkInterfaceUp;
  79. - (void)handleConnectionClosedByServer;
  80. - (void)handleConnectionErrorWithName:(NSString *)errorName;
  81. - (void)handleConnectionWasReEstablishedSuccessfully;
  82. @end
  83. @interface LPAccountAutomaticReconnectionContext () // Private Methods
  84. - (void)p_setObservedNetworkReachabilityRef:(SCNetworkReachabilityRef)reachabilityRef;
  85. - (void)p_setAutomaticReconnectionStatus:(LPAutoReconnectStatus)status;
  86. - (void)p_setupReconnectTimerWithTimeInterval:(NSTimeInterval)timeInterval;
  87. - (void)p_setupConnectionTimeoutTimerWithTimeInterval:(NSTimeInterval)timeInterval;
  88. - (void)p_reconnect:(NSTimer *)timer;
  89. - (void)p_reconnectTimedOut:(NSTimer *)timer;
  90. @end
  91. // Network Reachability Callback
  92. static void
  93. LPAccountServerHostReachabilityDidChange (SCNetworkReachabilityRef targetRef,
  94. SCNetworkConnectionFlags flags,
  95. void *info)
  96. {
  97. LPAccountAutomaticReconnectionContext *context = (LPAccountAutomaticReconnectionContext *)info;
  98. LPAccount *account = [context account];
  99. BOOL isReachableImmediately = ((flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired));
  100. LPDebugLog(REACHABILITY_DEBUG,
  101. @"Account %@: REACHABILITY: Did Change: Reachable? %@ (flags: %d)",
  102. account,
  103. (isReachableImmediately ? @"YES" : @"NO"),
  104. flags);
  105. if ([context lastNetworkConnectionFlags] != flags) {
  106. if (!isReachableImmediately) {
  107. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: REACHABILITY: Did Change: Setting as OFFLINE", account);
  108. [context handleNetworkInterfaceDown];
  109. }
  110. else {
  111. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: REACHABILITY: Did Change: Setting up reconnection timer.", account);
  112. [context handleNetworkInterfaceUp];
  113. }
  114. [context setLastNetworkConnectionFlags:flags];
  115. }
  116. }
  117. @implementation LPAccountAutomaticReconnectionContext
  118. - initForObservingConnectionWithLocalAddress:(NSString *)localAddress remoteAddress:(NSString *)remoteAddress account:(LPAccount *)account
  119. {
  120. if (self = [self init]) {
  121. m_account = [account retain];
  122. m_lastScheduledReconnectionTimer = nil;
  123. m_connectionTimeoutTimer = nil;
  124. [self p_setAutomaticReconnectionStatus:LPAutoReconnectIdle];
  125. [self setObservedConnectionWithLocalAddress:localAddress remoteAddress:remoteAddress];
  126. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: reconnection context initted for connection with local address: %@ / remote address: %@",
  127. m_account,
  128. (m_observedLocalAddress ? m_observedLocalAddress : @"(none)"),
  129. (m_observedRemoteAddress ? m_observedRemoteAddress : @"(none)"));
  130. }
  131. return self;
  132. }
  133. - (void)dealloc
  134. {
  135. [self p_setObservedNetworkReachabilityRef:NULL];
  136. [self cancelAllTimers];
  137. [m_account release];
  138. [m_observedLocalAddress release];
  139. [m_observedRemoteAddress release];
  140. [m_lastOnlineStatusMessage release];
  141. [super dealloc];
  142. }
  143. - (LPAccount *)account
  144. {
  145. return m_account;
  146. }
  147. - (NSString *)observedConnectionLocalAddress
  148. {
  149. return m_observedLocalAddress;
  150. }
  151. - (NSString *)observedConnectionRemoteAddress
  152. {
  153. return m_observedRemoteAddress;
  154. }
  155. - (void)p_setObservedNetworkReachabilityRef:(SCNetworkReachabilityRef)reachabilityRef
  156. {
  157. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: started observing a different reachability ref: %p", m_account, reachabilityRef);
  158. // Release the previous values...
  159. if (m_serverHostReachabilityRef != NULL) {
  160. SCNetworkReachabilityUnscheduleFromRunLoop( m_serverHostReachabilityRef,
  161. [[NSRunLoop currentRunLoop] getCFRunLoop],
  162. kCFRunLoopDefaultMode );
  163. CFRelease(m_serverHostReachabilityRef);
  164. m_serverHostReachabilityRef = NULL;
  165. }
  166. if (reachabilityRef != NULL) {
  167. m_serverHostReachabilityRef = CFRetain(reachabilityRef);
  168. SCNetworkReachabilityGetFlags(m_serverHostReachabilityRef, &m_lastNetworkConnectionFlags);
  169. SCNetworkReachabilityContext context = { 0, (void *)self, NULL, NULL, NULL };
  170. if ( SCNetworkReachabilitySetCallback( m_serverHostReachabilityRef,
  171. LPAccountServerHostReachabilityDidChange,
  172. &context) )
  173. {
  174. SCNetworkReachabilityScheduleWithRunLoop( m_serverHostReachabilityRef,
  175. [[NSRunLoop currentRunLoop] getCFRunLoop],
  176. kCFRunLoopDefaultMode );
  177. }
  178. }
  179. }
  180. - (void)setObservedConnectionWithLocalAddress:(NSString *)localAddress remoteAddress:(NSString *)remoteAddress
  181. {
  182. NSParameterAssert(localAddress);
  183. NSParameterAssert(remoteAddress);
  184. if (![localAddress isEqualToString:m_observedLocalAddress] || ![remoteAddress isEqualToString:m_observedRemoteAddress]) {
  185. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: setObservedConnectionWith... %@ / %@",
  186. m_account,
  187. (localAddress ? localAddress : @"(none)"),
  188. (remoteAddress ? remoteAddress : @"(none)"));
  189. // Release the previous values...
  190. [m_observedLocalAddress release];
  191. [m_observedRemoteAddress release];
  192. // ...and create some new ones.
  193. m_observedLocalAddress = [localAddress copy];
  194. m_observedRemoteAddress = [remoteAddress copy];
  195. // Setup the sockaddr structures
  196. struct sockaddr_in local_saddr, remote_saddr;
  197. bzero(&local_saddr, sizeof(struct sockaddr_in));
  198. bzero(&remote_saddr, sizeof(struct sockaddr_in));
  199. local_saddr.sin_len = remote_saddr.sin_len = sizeof(struct sockaddr_in);
  200. local_saddr.sin_family = remote_saddr.sin_family = AF_INET;
  201. inet_aton([localAddress UTF8String], &(local_saddr.sin_addr));
  202. inet_aton([remoteAddress UTF8String], &(remote_saddr.sin_addr));
  203. SCNetworkReachabilityRef reachabilityRef = SCNetworkReachabilityCreateWithAddressPair( CFAllocatorGetDefault(),
  204. (struct sockaddr *)&local_saddr,
  205. (struct sockaddr *)&remote_saddr );
  206. [self p_setObservedNetworkReachabilityRef:reachabilityRef];
  207. }
  208. }
  209. - (BOOL)isInTheMidstOfAutomaticReconnection
  210. {
  211. return (m_autoReconnectStatus != LPAutoReconnectIdle);
  212. }
  213. - (LPAutoReconnectStatus)automaticReconnectionStatus
  214. {
  215. return m_autoReconnectStatus;
  216. }
  217. - (void)p_setAutomaticReconnectionStatus:(LPAutoReconnectStatus)status
  218. {
  219. m_autoReconnectStatus = status;
  220. [[self account] p_setAutomaticReconnectionStatus:status];
  221. }
  222. - (SCNetworkConnectionFlags)lastNetworkConnectionFlags
  223. {
  224. return m_lastNetworkConnectionFlags;
  225. }
  226. - (void)setLastNetworkConnectionFlags:(SCNetworkConnectionFlags)flags
  227. {
  228. m_lastNetworkConnectionFlags = flags;
  229. }
  230. #pragma mark Timers
  231. - (void)cancelAllTimers
  232. {
  233. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: cancelling all timers", m_account);
  234. [m_connectionTimeoutTimer invalidate];
  235. [m_connectionTimeoutTimer release];
  236. m_connectionTimeoutTimer = nil;
  237. [m_lastScheduledReconnectionTimer invalidate];
  238. [m_lastScheduledReconnectionTimer release];
  239. m_lastScheduledReconnectionTimer = nil;
  240. }
  241. - (void)p_setupReconnectTimerWithTimeInterval:(NSTimeInterval)timeInterval
  242. {
  243. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: setting up reconnect timer with interval: %f s", m_account, timeInterval);
  244. [m_connectionTimeoutTimer invalidate];
  245. [m_connectionTimeoutTimer release];
  246. m_connectionTimeoutTimer = nil;
  247. [m_lastScheduledReconnectionTimer invalidate];
  248. [m_lastScheduledReconnectionTimer release];
  249. m_lastScheduledReconnectionTimer = [[NSTimer scheduledTimerWithTimeInterval:timeInterval
  250. target:self
  251. selector:@selector(p_reconnect:)
  252. userInfo:nil
  253. repeats:NO] retain];
  254. }
  255. - (void)p_setupConnectionTimeoutTimerWithTimeInterval:(NSTimeInterval)timeInterval
  256. {
  257. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: setting up connection timeout timer with interval: %f s", m_account, timeInterval);
  258. [m_connectionTimeoutTimer invalidate];
  259. [m_connectionTimeoutTimer release];
  260. m_connectionTimeoutTimer = [[NSTimer scheduledTimerWithTimeInterval:timeInterval
  261. target:self
  262. selector:@selector(p_reconnectTimedOut:)
  263. userInfo:nil
  264. repeats:NO] retain];
  265. }
  266. #pragma mark Callbacks for the reconnection timers
  267. - (void)p_reconnect:(NSTimer *)timer
  268. {
  269. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: REACHABILITY: Reconnection timer fired. Connecting...", m_account);
  270. [m_account p_setOnlineStatus:m_lastOnlineStatus message:m_lastOnlineStatusMessage saveToServer:NO];
  271. [self p_setupConnectionTimeoutTimerWithTimeInterval:30.0];
  272. }
  273. - (void)p_reconnectTimedOut:(NSTimer *)timer
  274. {
  275. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: REACHABILITY: Reconnection attempt timed out.", m_account);
  276. [m_account p_setOnlineStatus:LPStatusOffline message:nil saveToServer:NO];
  277. if (m_autoReconnectStatus != LPAutoReconnectIdle) {
  278. [self p_setupReconnectTimerWithTimeInterval:20.0];
  279. }
  280. }
  281. #pragma mark Event Handlers
  282. - (void)handleNetworkInterfaceDown
  283. {
  284. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: Interface going DOWN!", m_account);
  285. m_lastOnlineStatus = [m_account targetStatus];
  286. [m_lastOnlineStatusMessage release];
  287. m_lastOnlineStatusMessage = [[m_account p_statusMessage] copy];
  288. // Set our status to offline in case the core hasn't noticed that we no longer have a working network connection :)
  289. [m_account p_setOnlineStatus:LPStatusOffline message:nil saveToServer:NO];
  290. // Check whether there is an alternate interface immediately available.
  291. // The interface used for our connection may have gone down, but there may be another interface currently UP that allows us to
  292. // establish another connection to our server right away.
  293. BOOL alternateRouteExists = NO;
  294. SCNetworkReachabilityRef reachabilityRef = SCNetworkReachabilityCreateWithName( CFAllocatorGetDefault(),
  295. [[self observedConnectionRemoteAddress] UTF8String] );
  296. if (reachabilityRef) {
  297. SCNetworkConnectionFlags flags;
  298. SCNetworkReachabilityGetFlags(reachabilityRef, &flags);
  299. alternateRouteExists = ((flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired));
  300. }
  301. if (alternateRouteExists) {
  302. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: Alternate route exists!", m_account);
  303. [self p_setAutomaticReconnectionStatus:LPAutoReconnectUsingMultipleRetryAttempts];
  304. [self p_setObservedNetworkReachabilityRef:NULL];
  305. [self p_setupReconnectTimerWithTimeInterval:5.0];
  306. }
  307. else {
  308. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: No alternate route exists. Waiting for an interface to come up...", m_account);
  309. // Wait for some interface to go up
  310. [self p_setAutomaticReconnectionStatus:LPAutoReconnectWaitingForInterfaceToGoUp];
  311. // Cleanup the reconnection timers
  312. [self cancelAllTimers];
  313. // Stop observing the local/remote socket pair (which was specific for this interface) and simply start observing
  314. // the reachability of the server, no matter what route is taken to get to it.
  315. [self p_setObservedNetworkReachabilityRef:reachabilityRef];
  316. [m_observedLocalAddress release];
  317. m_observedLocalAddress = nil;
  318. }
  319. if (reachabilityRef)
  320. CFRelease(reachabilityRef);
  321. }
  322. - (void)handleNetworkInterfaceUp
  323. {
  324. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: Interface going UP!", m_account);
  325. if (m_autoReconnectStatus == LPAutoReconnectWaitingForInterfaceToGoUp) {
  326. if ([m_account status] == LPStatusOffline) {
  327. // Allow some seconds for things to calm down after the interface has just come up. iChat also does this
  328. // and it's probably a good idea.
  329. [self p_setupReconnectTimerWithTimeInterval:5.0];
  330. }
  331. }
  332. }
  333. - (void)handleConnectionClosedByServer
  334. {
  335. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: connection CLOSED by server!", m_account);
  336. // Start trying to connect repeatedly
  337. [self p_setAutomaticReconnectionStatus:LPAutoReconnectUsingMultipleRetryAttempts];
  338. m_lastOnlineStatus = [m_account targetStatus];
  339. [m_lastOnlineStatusMessage release];
  340. m_lastOnlineStatusMessage = [[m_account p_statusMessage] copy];
  341. [self p_setupReconnectTimerWithTimeInterval:20.0];
  342. }
  343. - (void)handleConnectionErrorWithName:(NSString *)errorName
  344. {
  345. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: connection ERROR from server: %@!", m_account, errorName);
  346. if (m_autoReconnectStatus != LPAutoReconnectIdle) {
  347. // Change our auto-reconnect mode
  348. [self p_setAutomaticReconnectionStatus:LPAutoReconnectUsingMultipleRetryAttempts];
  349. m_lastOnlineStatus = [m_account targetStatus];
  350. [m_lastOnlineStatusMessage release];
  351. m_lastOnlineStatusMessage = [[m_account p_statusMessage] copy];
  352. [self p_setupReconnectTimerWithTimeInterval:20.0];
  353. }
  354. }
  355. - (void)handleConnectionWasReEstablishedSuccessfully
  356. {
  357. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: connection REESTABLISHED successfully!", m_account);
  358. [self p_setAutomaticReconnectionStatus:LPAutoReconnectIdle];
  359. [self cancelAllTimers];
  360. [m_lastOnlineStatusMessage release];
  361. m_lastOnlineStatusMessage = nil;
  362. }
  363. @end
  364. #pragma mark -
  365. #pragma mark LPAccount
  366. // Notifications
  367. NSString *LPAccountWillChangeStatusNotification = @"LPAccountWillChangeStatusNotification";
  368. NSString *LPAccountDidChangeStatusNotification = @"LPAccountDidChangeStatusNotification";
  369. NSString *LPAccountDidChangeTransportInfoNotification = @"LPAccountDidChangeTransportInfoNotification";
  370. NSString *LPAccountDidReceiveXMLStringNotification = @"LPAccountDidReceiveXMLStringNotification";
  371. NSString *LPAccountDidSendXMLStringNotification = @"LPAccountDidSendXMLStringNotification";
  372. // Notifications user info dictionary keys
  373. NSString *LPXMLString = @"LPXMLString";
  374. @implementation LPAccount
  375. + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
  376. {
  377. if ([key isEqualToString:@"status"] || [key isEqualToString:@"statusMessage"] || [key isEqualToString:@"avatar"]) {
  378. return NO;
  379. } else {
  380. return [super automaticallyNotifiesObserversForKey:key];
  381. }
  382. }
  383. + (void)initialize
  384. {
  385. if (self == [LPAccount class]) {
  386. NSArray *statusKeyArray = [NSArray arrayWithObject:@"status"];
  387. [self setKeys:statusKeyArray triggerChangeNotificationsForDependentKey:@"online"];
  388. [self setKeys:statusKeyArray triggerChangeNotificationsForDependentKey:@"offline"];
  389. [self setKeys:statusKeyArray triggerChangeNotificationsForDependentKey:@"statusMessage"];
  390. }
  391. }
  392. - initWithUUID:(NSString *)uuid
  393. {
  394. return [self initWithUUID:uuid roster:[LPRoster roster]];
  395. }
  396. - initWithUUID:(NSString *)uuid roster:(LPRoster *)roster
  397. {
  398. if (self = [super init]) {
  399. m_UUID = [uuid copy];
  400. [self p_setStatus: LPStatusOffline];
  401. [self p_setStatusMessage: @""];
  402. [self p_setTargetStatus: LPStatusOffline];
  403. [self p_setAutomaticReconnectionStatus:LPAutoReconnectIdle];
  404. // Setup the avatar with the last known good image
  405. NSData *avatarData = [[NSUserDefaults standardUserDefaults] objectForKey:@"Last Known Self Avatar"];
  406. if (avatarData)
  407. m_avatar = [[NSUnarchiver unarchiveObjectWithData:avatarData] retain];
  408. [self setEnabled:NO];
  409. [self setJID:nil];
  410. [self setLocation:@""];
  411. [self setLocationUsesComputerName:YES];
  412. [self setCustomServerHost:@""];
  413. [self setUsesCustomServerHost:NO];
  414. [self setUsesSSL:NO];
  415. m_pubManager = [[LPPubManager alloc] init];
  416. m_transportAgentsRegistrationStatus = [[NSMutableDictionary alloc] init];
  417. m_smsCredit = m_smsNrOfFreeMessages = m_smsTotalSent = LPAccountSMSCreditUnknown;
  418. m_roster = [roster retain];
  419. // Register for notifications that will make us automatically go offline
  420. [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
  421. selector:@selector(workspaceWillSleep:)
  422. name:NSWorkspaceWillSleepNotification
  423. object:[NSWorkspace sharedWorkspace]];
  424. }
  425. return self;
  426. }
  427. - (void)dealloc
  428. {
  429. [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
  430. [LFAppController removeAccountWithUUID:[self UUID]];
  431. // Clear the observation of our notifications
  432. [self setDelegate:nil];
  433. [m_automaticReconnectionContext cancelAllTimers];
  434. [m_automaticReconnectionContext release];
  435. [m_pubManager release];
  436. [m_transportAgentsRegistrationStatus release];
  437. [m_UUID release];
  438. [m_description release];
  439. [m_name release];
  440. [m_JID release];
  441. [m_password release];
  442. [m_statusMessage release];
  443. [m_avatar release];
  444. [m_serverItemsInfo release];
  445. [m_sapoAgents release];
  446. [m_sapoChatOrderDict release];
  447. [m_customServerHost release];
  448. [m_lastAttemptedServerHost release];
  449. [m_lastSuccessfullyConnectedServerHost release];
  450. [m_lastRegisteredMSNEmail release];
  451. [m_lastRegisteredMSNPassword release];
  452. [m_roster release];
  453. [super dealloc];
  454. }
  455. #pragma mark -
  456. #pragma mark Private
  457. - (NSString *)p_computerNameForLocation
  458. {
  459. // Get the more user-friendly computer name set by the user in the "Sharing" System Preferences
  460. NSString *location = (NSString *)SCDynamicStoreCopyComputerName(NULL, NULL);
  461. [location autorelease];
  462. if ([location length] == 0)
  463. return [[NSProcessInfo processInfo] processName];
  464. else
  465. return location;
  466. }
  467. - (void)p_updateLocationFromChangedComputerName
  468. {
  469. if ([self locationUsesComputerName] && [self isOffline])
  470. [self setLocation:[self p_computerNameForLocation]];
  471. }
  472. /* This is the actual accessor for this value. The only thing it does is change the value of the "status" attribute
  473. in a KVO-compliant way. */
  474. - (void)p_setStatus:(LPStatus)theStatus
  475. {
  476. if (m_status != theStatus) {
  477. NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:theStatus] forKey:@"NewStatus"];
  478. [[NSNotificationCenter defaultCenter] postNotificationName:LPAccountWillChangeStatusNotification
  479. object:self
  480. userInfo:userInfo];
  481. [self willChangeValueForKey:@"status"];
  482. m_status = theStatus;
  483. [self didChangeValueForKey:@"status"];
  484. [[NSNotificationCenter defaultCenter] postNotificationName:LPAccountDidChangeStatusNotification
  485. object:self
  486. userInfo:userInfo];
  487. }
  488. }
  489. /* This is the actual accessor for this value. The only thing it does is change the value of the "statusMessage"
  490. attribute in a KVO-compliant way. */
  491. - (void)p_setStatusMessage:(NSString *)theStatusMessage
  492. {
  493. if (m_statusMessage != theStatusMessage) {
  494. [self willChangeValueForKey:@"statusMessage"];
  495. [m_statusMessage release];
  496. m_statusMessage = [theStatusMessage copy];
  497. [self didChangeValueForKey:@"statusMessage"];
  498. }
  499. }
  500. /* This is the actual accessor for this value. The method -statusMessage: returns the current status message
  501. suitable to be displayed to the user. For example, if the status is Offline, -statusMessage: will always return
  502. @"Offline" while this one actually returns the status message that was last set on this account. */
  503. - (NSString *)p_statusMessage
  504. {
  505. return m_statusMessage;
  506. }
  507. - (void)p_setTargetStatus:(LPStatus)theStatus
  508. {
  509. if (m_targetStatus != theStatus) {
  510. [self willChangeValueForKey:@"targetStatus"];
  511. m_targetStatus = theStatus;
  512. [self didChangeValueForKey:@"targetStatus"];
  513. }
  514. }
  515. - (void)p_setOnlineStatus:(LPStatus)theStatus message:(NSString *)theMessage saveToServer:(BOOL)saveFlag
  516. {
  517. [self p_setOnlineStatus:theStatus message:theMessage saveToServer:saveFlag alsoSaveStatusMessage:YES];
  518. }
  519. - (void)p_setOnlineStatus:(LPStatus)theStatus message:(NSString *)theMessage saveToServer:(BOOL)saveFlag alsoSaveStatusMessage:(BOOL)saveMsg
  520. {
  521. if (([self status] == LPStatusOffline) && (theStatus != LPStatusOffline)) {
  522. // We're going to get connected. Make sure we have a JID defined, at least.
  523. if ([[self JID] isEqualToString:@""]) {
  524. if ([m_delegate respondsToSelector:@selector(account:didReceiveErrorNamed:errorKind:errorCode:)]) {
  525. [m_delegate account:self didReceiveErrorNamed:@"NoJabberIDError" errorKind:0 errorCode:0];
  526. }
  527. }
  528. else {
  529. // If we use an empty server hostname, then the core will try to discover it using DNS SRV
  530. NSString *serverHost = ( ( [self p_lastConnectionAttemptDidFail] &&
  531. ([[self lastSuccessfullyConnectedServerHost] length] > 0) &&
  532. ![[self p_lastAttemptedServerHost] isEqualToString:[self lastSuccessfullyConnectedServerHost]] ) ?
  533. [self lastSuccessfullyConnectedServerHost] :
  534. ( [self usesCustomServerHost] ? [self customServerHost] : @"") );
  535. if (serverHost == nil) serverHost = @"";
  536. [self p_setLastAttemptedServerHost:serverHost];
  537. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: opening connection to %@", self, ([serverHost length] > 0 ? serverHost : @"(empty)"));
  538. [LFAppController setAttributesOfAccountWithUUID:[self UUID]
  539. JID:[self JID]
  540. host:serverHost
  541. password:[self password]
  542. resource:[self location]
  543. useSSL:[self usesSSL]];
  544. // Set the custom data transfer proxy only if the user has defined one
  545. NSString *dataTransferProxy = [[NSUserDefaults standardUserDefaults] objectForKey:@"DataTransferProxy"];
  546. if (dataTransferProxy && [dataTransferProxy length] > 0)
  547. [LFAppController setCustomDataTransferProxy:dataTransferProxy];
  548. // Reset the server items info and sapo agents info
  549. NSString *serverHostDomain = ([serverHost length] > 0 ? serverHost : [[self JID] JIDHostnameComponent]);
  550. [self willChangeValueForKey:@"serverItemsInfo"];
  551. [m_serverItemsInfo release];
  552. m_serverItemsInfo = [[LPServerItemsInfo alloc] initWithServerHost:serverHostDomain];
  553. [self didChangeValueForKey:@"serverItemsInfo"];
  554. [self willChangeValueForKey:@"sapoAgents"];
  555. [m_sapoAgents release];
  556. m_sapoAgents = [[LPSapoAgents alloc] initWithServerHost:serverHostDomain];
  557. [self didChangeValueForKey:@"sapoAgents"];
  558. [m_sapoChatOrderDict release]; m_sapoChatOrderDict = nil;
  559. [self p_setLastConnectionAttemptDidFail:NO];
  560. [self p_setStatus:LPStatusConnecting];
  561. [LFAppController setStatus:LPStatusStringFromStatus(theStatus) message:theMessage
  562. forAccountWithUUID:[self UUID]
  563. saveToServer:saveFlag alsoSaveStatusMessage:saveMsg];
  564. }
  565. }
  566. else {
  567. [LFAppController setStatus:LPStatusStringFromStatus(theStatus) message:theMessage
  568. forAccountWithUUID:[self UUID]
  569. saveToServer:saveFlag alsoSaveStatusMessage:saveMsg];
  570. }
  571. }
  572. - (void)p_setAutomaticReconnectionStatus:(LPAutoReconnectStatus)status
  573. {
  574. if (status != m_automaticReconnectionStatus) {
  575. [self willChangeValueForKey:@"automaticReconnectionStatus"];
  576. m_automaticReconnectionStatus = status;
  577. [self didChangeValueForKey:@"automaticReconnectionStatus"];
  578. }
  579. }
  580. /* This is the actual accessor for this value. The only thing it does is change the value of the "avatar"
  581. attribute in a KVO-compliant way. */
  582. - (void)p_setAvatar:(NSImage *)avatar
  583. {
  584. if (m_avatar != avatar) {
  585. [self willChangeValueForKey:@"avatar"];
  586. [m_avatar release];
  587. m_avatar = [avatar retain];
  588. [self didChangeValueForKey:@"avatar"];
  589. if (avatar) {
  590. // Save it in the user defaults as the last known good avatar
  591. NSData *archivedImage = [NSArchiver archivedDataWithRootObject:avatar];
  592. [[NSUserDefaults standardUserDefaults] setObject:archivedImage forKey:@"Last Known Self Avatar"];
  593. }
  594. else {
  595. [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"Last Known Self Avatar"];
  596. }
  597. }
  598. }
  599. - (void)p_changeAndAnnounceAvatar:(NSImage *)avatar
  600. {
  601. NSData *pngImageData = nil;
  602. if (avatar) {
  603. NSBitmapImageRep *bitmapRepresentation = [NSBitmapImageRep imageRepWithData:[avatar TIFFRepresentation]];
  604. pngImageData = [bitmapRepresentation representationUsingType:NSPNGFileType properties:nil];
  605. }
  606. // Send the image data to the core
  607. [LFAppController avatarPublish:pngImageData type:@"PNG"];
  608. }
  609. - (void)p_setSMSCredit:(int)credit freeMessages:(int)freeMsgs totalSent:(int)totalSent
  610. {
  611. [self willChangeValueForKey:@"SMSCreditValues"];
  612. m_smsCredit = credit;
  613. m_smsNrOfFreeMessages = freeMsgs;
  614. m_smsTotalSent = totalSent;
  615. [self didChangeValueForKey:@"SMSCreditValues"];
  616. }
  617. #pragma mark -
  618. #pragma mark Accessors
  619. - (NSString *)UUID
  620. {
  621. return [[m_UUID copy] autorelease];
  622. }
  623. - (NSString *)description
  624. {
  625. return [[m_description copy] autorelease];
  626. }
  627. - (void)setDescription:(NSString *)theDescription
  628. {
  629. if (m_description != theDescription) {
  630. [m_description release];
  631. m_description = [theDescription copy];
  632. }
  633. }
  634. - (BOOL)validateDescription:(id *)ioValue error:(NSError **)outError
  635. {
  636. if ([*ioValue length] == 0)
  637. *ioValue = [self JID];
  638. return YES;
  639. }
  640. - (BOOL)isEnabled
  641. {
  642. return m_enabled;
  643. }
  644. - (void)setEnabled:(BOOL)enabled
  645. {
  646. m_enabled = enabled;
  647. }
  648. - (NSString *)name
  649. {
  650. return [[m_name copy] autorelease];
  651. }
  652. - (void)setName:(NSString *)theName
  653. {
  654. if (m_name != theName) {
  655. [m_name release];
  656. m_name = [theName copy];
  657. }
  658. }
  659. - (NSString *)JID
  660. {
  661. return [[m_JID copy] autorelease];
  662. }
  663. - (void)setJID:(NSString *)theJID
  664. {
  665. if (m_JID != theJID) {
  666. NSString *oldHostname = [m_JID JIDHostnameComponent];
  667. // The description should be the same as the JID, unless it has already been customized.
  668. if ([m_description length] == 0 || [m_description isEqualToString:m_JID])
  669. [self setDescription:theJID];
  670. [m_JID release];
  671. m_JID = [theJID copy];
  672. if (![oldHostname isEqualToString:[m_JID JIDHostnameComponent]]) {
  673. [self p_setLastConnectionAttemptDidFail:NO];
  674. [self setLastSuccessfullyConnectedServerHost:nil];
  675. }
  676. }
  677. }
  678. - (NSString *)password
  679. {
  680. return [[m_password copy] autorelease];
  681. }
  682. - (void)setPassword:(NSString *)thePassword
  683. {
  684. if (m_password != thePassword) {
  685. [m_password release];
  686. m_password = [thePassword copy];
  687. }
  688. }
  689. - (NSString *)location
  690. {
  691. return [[m_location copy] autorelease];
  692. }
  693. - (void)setLocation:(NSString *)theLocation
  694. {
  695. if (m_location != theLocation) {
  696. [m_location release];
  697. m_location = [theLocation copy];
  698. }
  699. }
  700. - (BOOL)validateLocation:(id *)ioValue error:(NSError **)outError
  701. {
  702. if (*ioValue == nil)
  703. *ioValue = @"";
  704. return YES;
  705. }
  706. - (NSString *)customServerHost
  707. {
  708. return [[m_customServerHost copy] autorelease];
  709. }
  710. - (void)setCustomServerHost:(NSString *)theServerHost
  711. {
  712. if (m_customServerHost != theServerHost) {
  713. [m_customServerHost release];
  714. m_customServerHost = [theServerHost copy];
  715. if ([self usesCustomServerHost]) {
  716. [self p_setLastConnectionAttemptDidFail:NO];
  717. [self setLastSuccessfullyConnectedServerHost:nil];
  718. }
  719. }
  720. }
  721. - (BOOL)usesCustomServerHost
  722. {
  723. return m_usesCustomServerHost;
  724. }
  725. - (void)setUsesCustomServerHost:(BOOL)flag
  726. {
  727. if (m_usesCustomServerHost != flag) {
  728. [self p_setLastConnectionAttemptDidFail:NO];
  729. [self setLastSuccessfullyConnectedServerHost:nil];
  730. }
  731. m_usesCustomServerHost = flag;
  732. }
  733. - (BOOL)usesSSL
  734. {
  735. return m_usesSSL;
  736. }
  737. - (void)setUsesSSL:(BOOL)flag
  738. {
  739. m_usesSSL = flag;
  740. }
  741. - (BOOL)locationUsesComputerName
  742. {
  743. return m_locationUsesComputerName;
  744. }
  745. - (void)setLocationUsesComputerName:(BOOL)flag
  746. {
  747. // Was it just changed from OFF to ON?
  748. if (!m_locationUsesComputerName && flag)
  749. [self setLocation:[self p_computerNameForLocation]];
  750. m_locationUsesComputerName = flag;
  751. }
  752. - (NSString *)p_lastAttemptedServerHost
  753. {
  754. return [[m_lastAttemptedServerHost copy] autorelease];
  755. }
  756. - (void)p_setLastAttemptedServerHost:(NSString *)host
  757. {
  758. if (host != m_lastAttemptedServerHost) {
  759. [m_lastAttemptedServerHost release];
  760. m_lastAttemptedServerHost = [host copy];
  761. }
  762. }
  763. - (NSString *)lastSuccessfullyConnectedServerHost
  764. {
  765. return [[m_lastSuccessfullyConnectedServerHost copy] autorelease];
  766. }
  767. - (void)setLastSuccessfullyConnectedServerHost:(NSString *)host
  768. {
  769. if (host != m_lastSuccessfullyConnectedServerHost) {
  770. [m_lastSuccessfullyConnectedServerHost release];
  771. m_lastSuccessfullyConnectedServerHost = [host copy];
  772. }
  773. }
  774. - (BOOL)p_lastConnectionAttemptDidFail
  775. {
  776. return m_lastConnectionAttemptDidFail;
  777. }
  778. - (void)p_setLastConnectionAttemptDidFail:(BOOL)flag
  779. {
  780. m_lastConnectionAttemptDidFail = flag;
  781. }
  782. - (NSString *)lastRegisteredMSNEmail
  783. {
  784. return [[m_lastRegisteredMSNEmail copy] autorelease];
  785. }
  786. - (void)setLastRegisteredMSNEmail:(NSString *)username
  787. {
  788. if (m_lastRegisteredMSNEmail != username) {
  789. [m_lastRegisteredMSNEmail release];
  790. m_lastRegisteredMSNEmail = [username copy];
  791. }
  792. }
  793. - (NSString *)lastRegisteredMSNPassword
  794. {
  795. return [[m_lastRegisteredMSNPassword copy] autorelease];
  796. }
  797. - (void)setLastRegisteredMSNPassword:(NSString *)password
  798. {
  799. if (m_lastRegisteredMSNPassword != password) {
  800. [m_lastRegisteredMSNPassword release];
  801. m_lastRegisteredMSNPassword = [password copy];
  802. }
  803. }
  804. - (void)registerWithTransportAgent:(NSString *)transportAgent username:(NSString *)username password:(NSString *)password
  805. {
  806. if ([self isOnline]) {
  807. [self setLastRegisteredMSNEmail:username];
  808. [self setLastRegisteredMSNPassword:password];
  809. [LFAppController transportRegister:transportAgent username:username password:password onAccountWithUUID:[self UUID]];
  810. }
  811. }
  812. - (void)unregisterWithTransportAgent:(NSString *)transportAgent
  813. {
  814. if ([self isOnline]) {
  815. [LFAppController transportUnregister:transportAgent onAccountWithUUID:[self UUID]];
  816. }
  817. }
  818. - (NSString *)usernameRegisteredWithTransportAgent:(NSString *)transportAgent
  819. {
  820. return [[m_transportAgentsRegistrationStatus objectForKey:transportAgent] objectForKey:@"username"];
  821. }
  822. - (BOOL)isRegisteredWithTransportAgent:(NSString *)transportAgent
  823. {
  824. return [[[m_transportAgentsRegistrationStatus objectForKey:transportAgent] objectForKey:@"isRegistered"] boolValue];
  825. }
  826. - (BOOL)isLoggedInWithTransportAgent:(NSString *)transportAgent
  827. {
  828. return [[[m_transportAgentsRegistrationStatus objectForKey:transportAgent] objectForKey:@"isLoggedIn"] boolValue];
  829. }
  830. #pragma mark -
  831. - (LPStatus)status
  832. {
  833. return m_status;
  834. }
  835. - (NSString *)statusMessage
  836. {
  837. LPStatus myStatus = [self status];
  838. NSString *actualStatusMessage = [self p_statusMessage];
  839. if (myStatus == LPStatusConnecting) {
  840. // Return the default built-in status message for the current status
  841. return NSLocalizedStringFromTable( LPStatusStringFromStatus(myStatus), @"Status", @"" );
  842. }
  843. else {
  844. return [actualStatusMessage prettyStatusString];
  845. }
  846. }
  847. - (void)setStatusMessage:(NSString *)theStatusMessage
  848. {
  849. if ([self isOnline])
  850. [self setStatusMessage:theStatusMessage saveToServer:YES];
  851. }
  852. - (void)setStatusMessage:(NSString *)theStatusMessage saveToServer:(BOOL)saveFlag
  853. {
  854. if ([self isOnline])
  855. [self setTargetStatus:[self targetStatus] message:theStatusMessage
  856. saveToServer:saveFlag alsoSaveStatusMessage:YES];
  857. }
  858. - (LPStatus)targetStatus
  859. {
  860. return m_targetStatus;
  861. }
  862. - (void)setTargetStatus:(LPStatus)theStatus
  863. {
  864. [self setTargetStatus:theStatus saveToServer:YES];
  865. }
  866. - (void)setTargetStatus:(LPStatus)theStatus saveToServer:(BOOL)saveFlag
  867. {
  868. [self setTargetStatus:theStatus message:[self p_statusMessage] saveToServer:saveFlag alsoSaveStatusMessage:NO];
  869. }
  870. - (void)setTargetStatus:(LPStatus)theStatus message:(NSString *)theMessage saveToServer:(BOOL)saveFlag
  871. {
  872. [self setTargetStatus:theStatus message:theMessage saveToServer:saveFlag alsoSaveStatusMessage:YES];
  873. }
  874. - (void)setTargetStatus:(LPStatus)theStatus message:(NSString *)theMessage saveToServer:(BOOL)saveFlag alsoSaveStatusMessage:(BOOL)saveMsg
  875. {
  876. if (theStatus == LPStatusOffline) {
  877. [m_automaticReconnectionContext cancelAllTimers];
  878. [m_automaticReconnectionContext release];
  879. m_automaticReconnectionContext = nil;
  880. [self p_setAutomaticReconnectionStatus:LPAutoReconnectIdle];
  881. }
  882. [self p_setTargetStatus:theStatus];
  883. [self p_setOnlineStatus:theStatus message:theMessage saveToServer:saveFlag alsoSaveStatusMessage:saveMsg];
  884. }
  885. - (BOOL)isOnline
  886. {
  887. LPStatus myStatus = [self status];
  888. return ((myStatus != LPStatusOffline) && (myStatus != LPStatusConnecting));
  889. }
  890. - (BOOL)isOffline
  891. {
  892. return ([self status] == LPStatusOffline);
  893. }
  894. - (BOOL)isDebugger
  895. {
  896. return m_isDebugger;
  897. }
  898. - (BOOL)isTryingToAutoReconnect
  899. {
  900. return [m_automaticReconnectionContext isInTheMidstOfAutomaticReconnection];
  901. }
  902. - (LPAutoReconnectStatus)automaticReconnectionStatus
  903. {
  904. return m_automaticReconnectionStatus;
  905. }
  906. - (NSImage *)avatar
  907. {
  908. if (m_avatar)
  909. return [[m_avatar retain] autorelease];
  910. else
  911. return [NSImage imageNamed:@"defaultAvatar"];
  912. }
  913. - (void)setAvatar:(NSImage *)avatar
  914. {
  915. [self p_setAvatar:avatar];
  916. if ([self isOnline])
  917. [self p_changeAndAnnounceAvatar:avatar];
  918. }
  919. - (LPServerItemsInfo *)serverItemsInfo
  920. {
  921. return [[m_serverItemsInfo retain] autorelease];
  922. }
  923. - (LPSapoAgents *)sapoAgents
  924. {
  925. return [[m_sapoAgents retain] autorelease];
  926. }
  927. - (NSDictionary *)sapoChatOrderDictionary
  928. {
  929. return [[m_sapoChatOrderDict retain] autorelease];
  930. }
  931. - (LPPubManager *)pubManager
  932. {
  933. return [[m_pubManager retain] autorelease];
  934. }
  935. - (int)SMSCreditAvailable
  936. {
  937. return m_smsCredit;
  938. }
  939. - (int)nrOfFreeSMSMessagesAvailable
  940. {
  941. return m_smsNrOfFreeMessages;
  942. }
  943. - (int)nrOfSMSMessagesSentThisMonth
  944. {
  945. return m_smsTotalSent;
  946. }
  947. - (id)delegate
  948. {
  949. return m_delegate;
  950. }
  951. - (void)setDelegate:(id)delegate
  952. {
  953. NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
  954. [notifCenter removeObserver:m_delegate name:LPAccountWillChangeStatusNotification object:self];
  955. [notifCenter removeObserver:m_delegate name:LPAccountDidChangeStatusNotification object:self];
  956. [notifCenter removeObserver:m_delegate name:LPAccountDidChangeTransportInfoNotification object:self];
  957. [notifCenter removeObserver:m_delegate name:LPAccountDidReceiveXMLStringNotification object:self];
  958. [notifCenter removeObserver:m_delegate name:LPAccountDidSendXMLStringNotification object:self];
  959. m_delegate = delegate;
  960. if ([m_delegate respondsToSelector:@selector(accountWillChangeStatus:)]) {
  961. [notifCenter addObserver:m_delegate
  962. selector:@selector(accountWillChangeStatus:)
  963. name:LPAccountWillChangeStatusNotification
  964. object:self];
  965. }
  966. if ([m_delegate respondsToSelector:@selector(accountDidChangeStatus:)]) {
  967. [notifCenter addObserver:m_delegate
  968. selector:@selector(accountDidChangeStatus:)
  969. name:LPAccountDidChangeStatusNotification
  970. object:self];
  971. }
  972. if ([m_delegate respondsToSelector:@selector(accountDidChangeTransportInfo:)]) {
  973. [notifCenter addObserver:m_delegate
  974. selector:@selector(accountDidChangeTransportInfo:)
  975. name:LPAccountDidChangeTransportInfoNotification
  976. object:self];
  977. }
  978. if ([m_delegate respondsToSelector:@selector(accountDidReceiveXMLString:)]) {
  979. [notifCenter addObserver:m_delegate
  980. selector:@selector(accountDidReceiveXMLString:)
  981. name:LPAccountDidReceiveXMLStringNotification
  982. object:self];
  983. }
  984. if ([m_delegate respondsToSelector:@selector(accountDidSendXMLString:)]) {
  985. [notifCenter addObserver:m_delegate
  986. selector:@selector(accountDidSendXMLString:)
  987. name:LPAccountDidSendXMLStringNotification
  988. object:self];
  989. }
  990. }
  991. - (LPRoster *)roster
  992. {
  993. return [[m_roster retain] autorelease];
  994. }
  995. - (void)sendXMLString:(NSString *)str
  996. {
  997. [LFAppController accountSendXml:[self UUID] :str];
  998. }
  999. #pragma mark -
  1000. #pragma mark NSWorkspace Notifications
  1001. - (void)workspaceWillSleep:(NSNotification *)notification
  1002. {
  1003. [m_automaticReconnectionContext handleNetworkInterfaceDown];
  1004. }
  1005. @end
  1006. #pragma mark -
  1007. @implementation LPAccount (AccountsControllerInterface)
  1008. - (void)handleAccountConnectedToServerUsingLocalAddress:(NSString *)localAddress remoteAddress:(NSString *)remoteAddress
  1009. {
  1010. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: CONNECTED TO SERVER WITH ADDRESS PAIR: local: %@ / remote: %@",
  1011. self, localAddress, remoteAddress);
  1012. [self setLastSuccessfullyConnectedServerHost:remoteAddress];
  1013. if (m_automaticReconnectionContext == nil) {
  1014. m_automaticReconnectionContext = [[LPAccountAutomaticReconnectionContext alloc] initForObservingConnectionWithLocalAddress:localAddress
  1015. remoteAddress:remoteAddress
  1016. account:self];
  1017. } else {
  1018. /*
  1019. * Always update the hostname being observed by our auto-reconnect manager, even if we're always connecting to the
  1020. * same server. We may be receiving an IP address from the core in the 'serverHost' argument, and if the server hostname
  1021. * is associated with several different IP addresses we may have been connected to a different IP address this time.
  1022. */
  1023. [m_automaticReconnectionContext setObservedConnectionWithLocalAddress:localAddress remoteAddress:remoteAddress];
  1024. }
  1025. }
  1026. - (void)handleConnectionErrorWithName:(NSString *)errorName kind:(int)errorKind code:(int)errorCode
  1027. {
  1028. BOOL propagateConnectionError = YES;
  1029. static NSSet *recoverableConnectionErrors = nil;
  1030. if (recoverableConnectionErrors == nil) {
  1031. recoverableConnectionErrors = [[NSSet alloc] initWithObjects:@"GenericStreamError",
  1032. @"ConnectionTimeout", @"ConnectionRefused",
  1033. @"HostNotFound", @"UnknownHost", @"ProxyConnectionError", nil];
  1034. }
  1035. BOOL gotRecoverableError = (errorName != nil && [recoverableConnectionErrors containsObject:errorName]);
  1036. NSString *lastSuccessfullyConnectedServerHost = [self lastSuccessfullyConnectedServerHost];
  1037. // Can we try to recover from this error by trying to connect to our last known good server?
  1038. if (gotRecoverableError) {
  1039. [self p_setLastConnectionAttemptDidFail:YES];
  1040. // Have we still not attempted yet to connect to the last successfully connected server host?
  1041. if ([lastSuccessfullyConnectedServerHost length] > 0 &&
  1042. ![[self p_lastAttemptedServerHost] isEqualToString:lastSuccessfullyConnectedServerHost])
  1043. {
  1044. LPDebugLog(REACHABILITY_DEBUG,
  1045. @"Last connection attempt for account \"%@\" has failed. We will retry using the last server hostname"
  1046. @" that was known to work: %@",
  1047. self, [self lastSuccessfullyConnectedServerHost]);
  1048. // Retry with the last known good server (it will be selected automatically)
  1049. LPStatus status = [self targetStatus];
  1050. NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(setTargetStatus:)]];
  1051. [inv setTarget:self];
  1052. [inv setSelector:@selector(setTargetStatus:)];
  1053. [inv setArgument:&status atIndex:2];
  1054. [inv retainArguments];
  1055. [inv performSelector:@selector(invoke) withObject:nil afterDelay:0.0];
  1056. propagateConnectionError = NO;
  1057. }
  1058. }
  1059. if (propagateConnectionError) {
  1060. if ([m_automaticReconnectionContext isInTheMidstOfAutomaticReconnection]) {
  1061. LPDebugLog(REACHABILITY_DEBUG, @"Account %@: passing connection error to auto-reconnect-context.", self);
  1062. // Don't let the error reach the user-interface layer and notify our automatic reconnection context about the error
  1063. // so that it can autonomously decide what to do next.
  1064. [m_automaticReconnectionContext handleConnectionErrorWithName:errorName];
  1065. }
  1066. else {
  1067. if (gotRecoverableError &&
  1068. // Was our last connect attempt directed at the last successfully connected server host?
  1069. ([lastSuccessfullyConnectedServerHost length] > 0 &&
  1070. [[self p_lastAttemptedServerHost] isEqualToString:lastSuccessfullyConnectedServerHost])) {
  1071. LPDebugLog(REACHABILITY_DEBUG,
  1072. @"Account %@: passing connection closed event to auto-reconnect-context after "
  1073. @"getting an error.", self);
  1074. // Silently kick-off our automatic reconnection process if the connection was unexpectedly closed by the server
  1075. [m_automaticReconnectionContext handleConnectionClosedByServer];
  1076. }
  1077. else {
  1078. // Notify the delegate so that the error can be displayed to the user
  1079. if ([m_delegate respondsToSelector:@selector(account:didReceiveErrorNamed:errorKind:errorCode:)]) {
  1080. [m_delegate account:self didReceiveErrorNamed:errorName errorKind:errorKind errorCode:errorCode];
  1081. }
  1082. }
  1083. }
  1084. }
  1085. }
  1086. - (void)handleStatusUpdated:(NSString *)status message:(NSString *)statusMessage
  1087. {
  1088. LPStatus myNewStatus = LPStatusFromStatusString(status);
  1089. [self p_setStatus:myNewStatus];
  1090. [self p_setStatusMessage:statusMessage];
  1091. if ([m_automaticReconnectionContext isInTheMidstOfAutomaticReconnection] && myNewStatus != LPStatusOffline) {
  1092. [m_automaticReconnectionContext handleConnectionWasReEstablishedSuccessfully];
  1093. }
  1094. // Update the location name if we need to (because the computer name may have changed, but we shouldn't modify the
  1095. // location name while we're online as it is used for the jabber resource).
  1096. if (myNewStatus == LPStatusOffline && [self locationUsesComputerName]) {
  1097. NSString *computerName = [self p_computerNameForLocation];
  1098. if (![computerName isEqualToString:[self location]]) {
  1099. [self setLocation:computerName];
  1100. }
  1101. }
  1102. }
  1103. - (void)handleSavedStatusReceived:(NSString *)status message:(NSString *)statusMessage
  1104. {
  1105. if ([m_delegate respondsToSelector:@selector(account:didReceiveSavedStatus:message:)]) {
  1106. [m_delegate account:self didReceiveSavedStatus:LPStatusFromStatusString(status) message:statusMessage];
  1107. }
  1108. }
  1109. - (void)handleSelfAvatarChangedWithType:(NSString *)type data:(NSData *)avatarData
  1110. {
  1111. NSImage *avatarImage = [[NSImage alloc] initWithData:avatarData];
  1112. [self p_setAvatar:avatarImage];
  1113. [avatarImage release];
  1114. }
  1115. - (void)handleServerItemsUpdated:(NSArray *)items
  1116. {
  1117. [m_serverItemsInfo handleServerItemsUpdated:items];
  1118. }
  1119. - (void)handleInfoUpdatedForServerItem:(NSString *)item withName:(NSString *)name identities:(NSArray *)identities features:(NSArray *)features
  1120. {
  1121. [m_serverItemsInfo handleInfoUpdatedForServerItem:item withName:name identities:identities features:features];
  1122. }
  1123. - (void)handleSapoAgentsUpdated:(NSDictionary *)sapoAgents
  1124. {
  1125. [m_sapoAgents handleSapoAgentsUpdated:sapoAgents];
  1126. }
  1127. - (void)handleAccountXmlIO:(NSString *)xml isInbound:(BOOL)isInbound
  1128. {
  1129. [[NSNotificationCenter defaultCenter] postNotificationName:( isInbound ?
  1130. LPAccountDidReceiveXMLStringNotification :
  1131. LPAccountDidSendXMLStringNotification )
  1132. object:self
  1133. userInfo:[NSDictionary dictionaryWithObject:xml forKey:LPXMLString]];
  1134. }
  1135. - (void)handleReceivedOfflineMessageAt:(NSString *)timestamp fromJID:(NSString *)jid nickname:(NSString *)nick subject:(NSString *)subject plainTextMessage:(NSString *)plainTextMessage XHTMLMessaage:(NSString *)XHTMLMessage URLs:(NSArray *)URLs
  1136. {
  1137. if ([m_delegate respondsToSelector:@selector(account:didReceiveOfflineMessageFromJID:nick:timestamp:subject:plainTextVariant:XHTMLVariant:URLs:)]) {
  1138. [m_delegate account:self didReceiveOfflineMessageFromJID:jid nick:nick timestamp:timestamp subject:subject plainTextVariant:plainTextMessage XHTMLVariant:XHTMLMessage URLs:URLs];
  1139. }
  1140. }
  1141. - (void)handleReceivedHeadlineNotificationMessageFromChannel:(NSString *)channel itemURL:(NSString *)item_url flashURL:(NSString *)flash_url iconURL:(NSString *)icon_url nickname:(NSString *)nick subject:(NSString *)subject plainTextMessage:(NSString *)plainTextMessage XHTMLMessage:(NSString *)XHTMLMessage
  1142. {
  1143. if ([m_delegate respondsToSelector:@selector(account:didReceiveHeadlineNotificationMessageFromChannel:subject:body:itemURL:flashURL:iconURL:)]) {
  1144. #warning We're trimming whitespace just because of the notifications from JN, which always start with a bunch of spaces.
  1145. NSString *trimmedSubject = [subject stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  1146. [m_delegate account:self didReceiveHeadlineNotificationMessageFromChannel:channel
  1147. subject:trimmedSubject body:plainTextMessage itemURL:item_url flashURL:flash_url iconURL:icon_url];
  1148. }
  1149. }
  1150. - (void)handleReceivedInvitationToGroupChat:(NSString *)roomJID from:(NSString *)sender reason:(NSString *)reason password:(NSString *)password
  1151. {
  1152. if ([m_delegate respondsToSelector:@selector(account:didReceiveInvitationToRoomWithJID:from:reason:password:)]) {
  1153. [m_delegate account:self didReceiveInvitationToRoomWithJID:roomJID from:sender reason:reason password:password];
  1154. }
  1155. }
  1156. - (void)handleSMSCreditUpdated:(int)credit freeMessages:(int)free_msgs totalSent:(int)total_sent_this_month
  1157. {
  1158. [self p_setSMSCredit:credit freeMessages:free_msgs totalSent:total_sent_this_month];
  1159. }
  1160. - (void)handleSMSSentWithResult:(int)result nrUsedMessages:(int)nr_used_msgs nrUsedChars:(int)nr_used_chars
  1161. destinationPhoneNr:(NSString *)destination_phone_nr body:(NSString *)body
  1162. credit:(int)credit freeMessages:(int)free_msgs totalSent:(int)total_sent_this_month
  1163. {
  1164. NSString *theJID = [[destination_phone_nr userPresentablePhoneNrRepresentation] internalPhoneJIDRepresentation];
  1165. NSString *address = [theJID bareJIDComponent];
  1166. LPContactEntry *entry = [[self roster] contactEntryForAddress:address account:self];
  1167. NSAssert1(entry != nil, @"handleSMSSentWithResult:... JID <%@> isn't in the roster (not even invisible).", theJID);
  1168. [[[LPChatsManager chatsManager] existingChatOrMakeNewWithContact:[entry contact]] handleResultOfSMSSentTo:theJID
  1169. withBody:body
  1170. resultCode:result
  1171. nrUsedMsgs:nr_used_msgs
  1172. nrUsedChars:nr_used_chars
  1173. newCredit:credit
  1174. newFreeMessages:free_msgs
  1175. newTotalSentThisMonth:total_sent_this_month];
  1176. // Also update the global credit if we can
  1177. if (credit >= 0)
  1178. [self handleSMSCreditUpdated:credit freeMessages:free_msgs totalSent:total_sent_this_month];
  1179. }
  1180. - (void)handleSMSReceivedAt:(NSString *)date_received fromPhoneNr:(NSString *)source_phone_nr body:(NSString *)body
  1181. credit:(int)credit freeMessages:(int)free_msgs totalSent:(int)total_sent_this_month
  1182. {
  1183. NSString *theJID = [[source_phone_nr userPresentablePhoneNrRepresentation] internalPhoneJIDRepresentation];
  1184. NSString *address = [theJID bareJIDComponent];
  1185. LPContactEntry *entry = [[self roster] contactEntryForAddress:address account:self];
  1186. NSAssert1(entry != nil, @"handleSMSReceivedAt:... JID <%@> isn't in the roster (not even invisible).", theJID);
  1187. [[[LPChatsManager chatsManager] existingChatOrMakeNewWithContact:[entry contact]] handleSMSReceivedFrom:theJID
  1188. withBody:body
  1189. dateString:date_received
  1190. newCredit:credit
  1191. newFreeMessages:free_msgs
  1192. newTotalSentThisMonth:total_sent_this_month];
  1193. // Also update the global credit if we can
  1194. if (credit >= 0)
  1195. [self handleSMSCreditUpdated:credit freeMessages:free_msgs totalSent:total_sent_this_month];
  1196. }
  1197. //- (void)leapfrogBridge_serverItemsUpdated:(NSArray *)serverItems
  1198. //{
  1199. // [m_serverItemsInfo handleServerItemsUpdated:serverItems];
  1200. //}
  1201. //
  1202. //
  1203. //- (void)leapfrogBridge_serverItemInfoUpdated:(NSString *)item :(NSString *)name :(NSArray *)features
  1204. //{
  1205. // [m_serverItemsInfo handleInfoUpdatedForServerItem:item withName:name features:features];
  1206. //}
  1207. //
  1208. //
  1209. //- (void)leapfrogBridge_sapoAgentsUpdated:(NSDictionary *)sapoAgentsDescription
  1210. //{
  1211. // [m_sapoAgents handleSapoAgentsUpdated:sapoAgentsDescription];
  1212. //}
  1213. //
  1214. //
  1215. //- (void)leapfrogBridge_chatRoomsListReceived:(NSString *)host :(NSArray *)roomsList
  1216. //{
  1217. // // DEBUG
  1218. // //NSLog(@"MUC ITEMS UPDATED:\nHost: %@\nRooms: %@\n", host, roomsList);
  1219. //
  1220. // if ([m_delegate respondsToSelector:@selector(account:didReceiveChatRoomsList:forHost:)]) {
  1221. // [m_delegate account:self didReceiveChatRoomsList:roomsList forHost:host];
  1222. // }
  1223. //}
  1224. //
  1225. //
  1226. //- (void)leapfrog…

Large files files are truncated, but you can click here to view the full file