From 1f0dde0452519496a3d361ad6ddb38731c350a7e Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Sun, 27 May 2012 22:33:26 +0000 Subject: Improve connection handling and editing: - Fix long-standing intermittent crashes caused by connection errors after SSH tunnels were established - Fix edits causing keychain -25299 errors (Issue #1340) - Allow changes of favourite type to be saved rather than disassociating the edit from the selection - Fix the favourites view scrolling to the top when there's no selection and connection details are being edited - Fix some issues with automatic naming of connections on connection type change --- Source/SPConnectionController.h | 1 - Source/SPConnectionController.m | 7 +++++-- Source/SPConnectionControllerDelegate.m | 4 ---- Source/SPConnectionControllerInitializer.m | 6 +++++- Source/SPConnectionHandler.m | 7 ++++--- Source/SPKeychain.m | 8 ++++++++ Source/SPSSHTunnel.m | 9 +++++++-- 7 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Source/SPConnectionController.h b/Source/SPConnectionController.h index 63df0551..b7aeb7c8 100644 --- a/Source/SPConnectionController.h +++ b/Source/SPConnectionController.h @@ -69,7 +69,6 @@ NSUserDefaults *prefs; #ifndef SP_REFACTOR /* ivars */ - BOOL automaticFavoriteSelection; BOOL cancellingConnection; BOOL isConnecting; diff --git a/Source/SPConnectionController.m b/Source/SPConnectionController.m index 212df1da..68d7bb16 100644 --- a/Source/SPConnectionController.m +++ b/Source/SPConnectionController.m @@ -468,7 +468,6 @@ static NSComparisonResult _compareFavoritesUsingKey(id favorite1, id favorite2, */ - (void)updateFavoriteSelection:(id)sender { - automaticFavoriteSelection = YES; // Clear the keychain referral items as appropriate if (connectionKeychainID) [connectionKeychainID release], connectionKeychainID = nil; @@ -1218,7 +1217,7 @@ static NSComparisonResult _compareFavoritesUsingKey(id favorite1, id favorite2, } // Update the name for newly added favorites if not already touched by the user, by triggering a KVO update - if (!favoriteNameFieldWasTouched) { + if (![[self name] length]) { [self setName:[NSString stringWithFormat:@"%@@%@", ([favorite objectForKey:SPFavoriteUserKey]) ? [favorite objectForKey:SPFavoriteUserKey] : @"", ((previousType == SPSocketConnection) ? @"localhost" : @@ -1290,6 +1289,10 @@ static NSComparisonResult _compareFavoritesUsingKey(id favorite1, id favorite2, */ - (void)_scrollToSelectedNode { + + // Don't scroll if no node is currently selected + if ([favoritesOutlineView selectedRow] == -1) return; + [favoritesOutlineView scrollRowToVisible:[favoritesOutlineView selectedRow]]; } diff --git a/Source/SPConnectionControllerDelegate.m b/Source/SPConnectionControllerDelegate.m index 18c43f1b..a1a12c1c 100644 --- a/Source/SPConnectionControllerDelegate.m +++ b/Source/SPConnectionControllerDelegate.m @@ -437,10 +437,6 @@ static NSString *SPDatabaseImage = @"database-small"; { NSInteger selectedTabView = [tabView indexOfTabViewItem:tabViewItem]; - // Deselect any selected favorite for manual changes - if (!automaticFavoriteSelection) [favoritesOutlineView deselectAll:self]; - automaticFavoriteSelection = NO; - if (selectedTabView == previousType) return; [self resizeTabViewToConnectionType:selectedTabView animating:YES]; diff --git a/Source/SPConnectionControllerInitializer.m b/Source/SPConnectionControllerInitializer.m index 7a50b003..09847b98 100644 --- a/Source/SPConnectionControllerInitializer.m +++ b/Source/SPConnectionControllerInitializer.m @@ -73,7 +73,6 @@ static NSString *SPConnectionViewNibName = @"ConnectionView"; cancellingConnection = NO; mySQLConnectionCancelled = NO; favoriteNameFieldWasTouched = YES; - automaticFavoriteSelection = NO; [self loadNib]; [self registerForNotifications]; @@ -148,6 +147,11 @@ static NSString *SPConnectionViewNibName = @"ConnectionView"; object:nil]; // Registered to be notified of changes to connection information + [self addObserver:self + forKeyPath:SPFavoriteTypeKey + options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) + context:NULL]; + [self addObserver:self forKeyPath:SPFavoriteNameKey options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) diff --git a/Source/SPConnectionHandler.m b/Source/SPConnectionHandler.m index aec8a61e..ec478b74 100644 --- a/Source/SPConnectionHandler.m +++ b/Source/SPConnectionHandler.m @@ -29,6 +29,7 @@ #import "SPSSHTunnel.h" #import "SPKeychain.h" #import "RegexKitLite.h" +#import "SPCategoryAdditions.h" #import @@ -176,7 +177,7 @@ static NSString *SPLocalhostAddress = @"127.0.0.1"; // Tidy up isConnecting = NO; - if (sshTunnel) [sshTunnel release], sshTunnel = nil; + if (sshTunnel) [sshTunnel disconnect], [sshTunnel release], sshTunnel = nil; [mySQLConnection release], mySQLConnection = nil; if (!cancellingConnection) [self _restoreConnectionInterface]; @@ -409,7 +410,7 @@ static NSString *SPLocalhostAddress = @"127.0.0.1"; // Inform the delegate that the connection attempt failed if (delegate && [delegate respondsToSelector:@selector(connectionControllerConnectAttemptFailed:)]) { - [delegate connectionControllerConnectAttemptFailed:self]; + [[(NSObject *)delegate onMainThread] connectionControllerConnectAttemptFailed:self]; } // Only display the connection error message if there is a window visible and the connection attempt @@ -423,7 +424,7 @@ static NSString *SPLocalhostAddress = @"127.0.0.1"; * Alert sheet callback method - invoked when an error sheet is closed. */ - (void)connectionFailureSheetDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo -{ +{ // Restore the passwords from keychain for editing if appropriate if (connectionKeychainItemName) { [self setPassword:[keychain getPasswordForName:connectionKeychainItemName account:connectionKeychainItemAccount]]; diff --git a/Source/SPKeychain.m b/Source/SPKeychain.m index aa38f7b5..3a66b327 100644 --- a/Source/SPKeychain.m +++ b/Source/SPKeychain.m @@ -283,6 +283,14 @@ status = SecKeychainItemModifyAttributesAndData(itemRef, &attList, (UInt32)strlen([password UTF8String]), [password UTF8String]); if (status != noErr) { + + // An error of -25299 indicates that the keychain item is a duplicate. As connection names include a unique ID, + // this indicates an issue when previously altering keychain items; delete the old item and try again. + if ((int)status == -25299) { + [self deletePasswordForName:newName account:newAccount]; + return [self updateItemWithName:name account:account toName:newName account:newAccount password:password]; + } + NSLog(@"Error (%i) while updating keychain item for name: %@ account: %@", (int)status, name, account); SPBeginAlertSheet(NSLocalizedString(@"Error updating Keychain item", @"error updating keychain item message"), NSLocalizedString(@"OK", @"OK button"), diff --git a/Source/SPSSHTunnel.m b/Source/SPSSHTunnel.m index 106f8774..083a1000 100644 --- a/Source/SPSSHTunnel.m +++ b/Source/SPSSHTunnel.m @@ -390,11 +390,15 @@ { if (connectionState == SPMySQLProxyIdle) return; + // If there's a delegate set, clear it to prevent unexpected state change messaging + if (delegate) { + delegate = nil; + stateChangeSelector = NULL; + } + // Before terminating the tunnel, check that it's actually running. This is to accommodate tunnels which // suddenly disappear as a result of network disconnections. if ([task isRunning]) [task terminate]; - - if (delegate) [delegate performSelectorOnMainThread:stateChangeSelector withObject:self waitUntilDone:NO]; } /* @@ -663,6 +667,7 @@ delegate = nil; [[NSNotificationCenter defaultCenter] removeObserver:self]; if (connectionState != SPMySQLProxyIdle) [self disconnect]; + [NSObject cancelPreviousPerformRequestsWithTarget:self]; [sshHost release]; [sshLogin release]; [remoteHost release]; -- cgit v1.2.3