diff options
-rw-r--r-- | Interfaces/English.lproj/SSHQuestionDialog.xib | 141 | ||||
-rw-r--r-- | Source/SPSSHTunnel.h | 7 | ||||
-rw-r--r-- | Source/SPSSHTunnel.m | 139 |
3 files changed, 193 insertions, 94 deletions
diff --git a/Interfaces/English.lproj/SSHQuestionDialog.xib b/Interfaces/English.lproj/SSHQuestionDialog.xib index 9941eddb..fc8bd36f 100644 --- a/Interfaces/English.lproj/SSHQuestionDialog.xib +++ b/Interfaces/English.lproj/SSHQuestionDialog.xib @@ -12,6 +12,7 @@ </object> <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="368"/> <integer value="469"/> </object> <object class="NSArray" key="IBDocument.PluginDependencies"> @@ -30,7 +31,7 @@ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSCustomObject" id="1021"> - <string key="NSClassName">NSObject</string> + <string key="NSClassName">SPSSHTunnel</string> </object> <object class="NSCustomObject" id="1014"> <string key="NSClassName">FirstResponder</string> @@ -48,7 +49,7 @@ <nil key="NSViewClass"/> <string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string> <object class="NSView" key="NSWindowView" id="414427165"> - <nil key="NSNextResponder"/> + <reference key="NSNextResponder"/> <int key="NSvFlags">256</int> <object class="NSMutableArray" key="NSSubviews"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -199,6 +200,7 @@ </object> </object> <string key="NSFrameSize">{620, 209}</string> + <reference key="NSSuperview"/> </object> <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string> <string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string> @@ -441,38 +443,6 @@ <int key="connectionID">465</int> </object> <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">closeSheet:</string> - <reference key="source" ref="1021"/> - <reference key="destination" ref="819605912"/> - </object> - <int key="connectionID">466</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">closeSheet:</string> - <reference key="source" ref="1021"/> - <reference key="destination" ref="472545742"/> - </object> - <int key="connectionID">467</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">closeSheet:</string> - <reference key="source" ref="1021"/> - <reference key="destination" ref="881553485"/> - </object> - <int key="connectionID">480</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> - <string key="label">closeSheet:</string> - <reference key="source" ref="1021"/> - <reference key="destination" ref="920337090"/> - </object> - <int key="connectionID">481</int> - </object> - <object class="IBConnectionRecord"> <object class="IBOutletConnection" key="connection"> <string key="label">sshPasswordDialog</string> <reference key="source" ref="1021"/> @@ -504,6 +474,38 @@ </object> <int key="connectionID">493</int> </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">closeSSHPasswordSheet:</string> + <reference key="source" ref="1021"/> + <reference key="destination" ref="881553485"/> + </object> + <int key="connectionID">494</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">closeSSHPasswordSheet:</string> + <reference key="source" ref="1021"/> + <reference key="destination" ref="920337090"/> + </object> + <int key="connectionID">495</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">closeSSHQuestionSheet:</string> + <reference key="source" ref="1021"/> + <reference key="destination" ref="819605912"/> + </object> + <int key="connectionID">496</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">closeSSHQuestionSheet:</string> + <reference key="source" ref="1021"/> + <reference key="destination" ref="472545742"/> + </object> + <int key="connectionID">497</int> + </object> </object> <object class="IBMutableOrderedSet" key="objectRecords"> <object class="NSArray" key="orderedObjects"> @@ -826,9 +828,9 @@ <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>{{218, 467}, {471, 209}}</string> + <string>{{127, 251}, {471, 209}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>{{218, 467}, {471, 209}}</string> + <string>{{127, 251}, {471, 209}}</string> <boolean value="NO"/> <string>{{11, 666}, {480, 270}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> @@ -866,7 +868,7 @@ </object> </object> <nil key="sourceID"/> - <int key="maxID">493</int> + <int key="maxID">497</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> <object class="NSMutableArray" key="referencedPartialClassDescriptions"> @@ -991,6 +993,50 @@ <string key="minorKey">Source/SPWindowAdditions.h</string> </object> </object> + <object class="IBPartialClassDescription"> + <string key="className">SPSSHTunnel</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="actions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>closeSSHPasswordSheet:</string> + <string>closeSSHQuestionSheet:</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>id</string> + <string>id</string> + </object> + </object> + <object class="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>delegate</string> + <string>sshPasswordDialog</string> + <string>sshPasswordField</string> + <string>sshPasswordKeychainCheckbox</string> + <string>sshPasswordText</string> + <string>sshQuestionDialog</string> + <string>sshQuestionText</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>id</string> + <string>NSWindow</string> + <string>NSSecureTextField</string> + <string>NSButton</string> + <string>NSTextField</string> + <string>NSWindow</string> + <string>NSTextField</string> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">Source/SPSSHTunnel.h</string> + </object> + </object> </object> <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -1046,6 +1092,13 @@ </object> </object> <object class="IBPartialClassDescription"> + <string key="className">NSApplication</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">BWToolkitFramework.framework/Headers/NSApplication+BWAdditions.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> <string key="className">NSButton</string> <string key="superclassName">NSControl</string> <object class="IBClassDescriptionSource" key="sourceIdentifier"> @@ -1515,6 +1568,13 @@ <reference key="sourceIdentifier" ref="295094819"/> </object> <object class="IBPartialClassDescription"> + <string key="className">NSView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">BWToolkitFramework.framework/Headers/NSView+BWAdditions.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> <string key="className">NSWindow</string> <object class="IBClassDescriptionSource" key="sourceIdentifier"> <string key="majorKey">IBFrameworkSource</string> @@ -1536,6 +1596,13 @@ <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string> </object> </object> + <object class="IBPartialClassDescription"> + <string key="className">NSWindow</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">BWToolkitFramework.framework/Headers/NSWindow+BWAdditions.h</string> + </object> + </object> </object> </object> <int key="IBDocument.localizationMode">0</int> diff --git a/Source/SPSSHTunnel.h b/Source/SPSSHTunnel.h index 1a061619..836611f3 100644 --- a/Source/SPSSHTunnel.h +++ b/Source/SPSSHTunnel.h @@ -67,6 +67,10 @@ enum spsshtunnel_password_modes NSInteger localPort; NSInteger localPortFallback; NSInteger connectionState; + + BOOL isAnswerAvailable; + NSCondition *answerAvailableCondition; + NSString *currentKeyName; } - (id) initToHost:(NSString *) theHost port:(NSInteger) thePort login:(NSString *) theLogin tunnellingToPort:(NSInteger) targetPort onHost:(NSString *) targetHost; @@ -88,6 +92,7 @@ enum spsshtunnel_password_modes - (void) workerGetResponseForQuestion:(NSString *)theQuestion; - (NSString *) getPasswordForQuery:(NSString *)theQuery verificationHash:(NSString *)theHash; - (void) workerGetPasswordForQuery:(NSString *)theQuery; -- (IBAction) closeSheet:(id)sender; +- (IBAction) closeSSHQuestionSheet:(id)sender; +- (IBAction) closeSSHPasswordSheet:(id)sender; @end diff --git a/Source/SPSSHTunnel.m b/Source/SPSSHTunnel.m index 4779e6a1..9b53adda 100644 --- a/Source/SPSSHTunnel.m +++ b/Source/SPSSHTunnel.m @@ -469,9 +469,24 @@ */ - (BOOL) getResponseForQuestion:(NSString *)theQuestion { + // prepare the condition + [answerAvailableCondition lock]; + isAnswerAvailable = NO; + + // request an answer on the main thread (UI stuff must be done on main thread) [self performSelectorOnMainThread:@selector(workerGetResponseForQuestion:) withObject:theQuestion waitUntilDone:YES]; - return requestedResponse; + // wait until an answer is available + while (!isAnswerAvailable) [answerAvailableCondition wait]; + + // save the answer + BOOL response = requestedResponse; + + //unlock condition + [answerAvailableCondition unlock]; + + //return the answer + return response; } - (void) workerGetResponseForQuestion:(NSString *)theQuestion { @@ -479,29 +494,28 @@ NSSize questionTextSize; NSRect windowFrameRect; - // Ask how to proceed, sizing the window appropriately to fit the question + // set up the question window [sshQuestionText setStringValue:theQuestion]; questionTextSize = [[sshQuestionText cell] cellSizeForBounds:NSMakeRect(0, 0, [sshQuestionText bounds].size.width, 500)]; windowFrameRect = [sshQuestionDialog frame]; windowFrameRect.size.height = ((questionTextSize.height < 100)?100:questionTextSize.height) + 70 + ([sshPasswordDialog isSheet]?0:22); [sshQuestionDialog setFrame:windowFrameRect display:NO]; + + //show the question window [NSApp beginSheet:sshQuestionDialog modalForWindow:parentWindow modalDelegate:self didEndSelector:nil contextInfo:nil]; - NSInteger sshQueryResponseCode = [NSApp runModalForWindow:sshQuestionDialog]; - [NSApp endSheet:sshQuestionDialog]; +} +/* + * Ends an existing modal session + */ +- (IBAction) closeSSHQuestionSheet:(id)sender +{ + [answerAvailableCondition lock]; + requestedResponse = [sender tag]==1 ? YES : NO; + [NSApp endSheet:sshQuestionDialog]; [sshQuestionDialog orderOut:nil]; - - switch (sshQueryResponseCode) { - - // Yes - case 1: - requestedResponse = YES; - return; - - // No - default: - requestedResponse = NO; - return; - } + isAnswerAvailable = YES; + [answerAvailableCondition signal]; + [answerAvailableCondition unlock]; } /* @@ -512,30 +526,44 @@ { if (![theHash isEqualToString:tunnelConnectionVerifyHash]) return nil; - NSString *thePassword; - + // prepare the condition + [answerAvailableCondition lock]; + isAnswerAvailable = NO; + + // request password on the main thread (UI stuff must be done on main thread) [self performSelectorOnMainThread:@selector(workerGetPasswordForQuery:) withObject:theQuery waitUntilDone:YES]; - if (!requestedPassphrase) return nil; - thePassword = [NSString stringWithString:requestedPassphrase]; - [requestedPassphrase release], requestedPassphrase = nil; + // wait until an answer is available + while (!isAnswerAvailable) [answerAvailableCondition wait]; + + // save the answer + NSString *thePassword = nil; + if (requestedPassphrase) { + thePassword = [NSString stringWithString:requestedPassphrase]; + [requestedPassphrase release], requestedPassphrase = nil; + } + + //unlock condition + [answerAvailableCondition unlock]; + + //return the answer return thePassword; } - (void) workerGetPasswordForQuery:(NSString *)theQuery { NSSize queryTextSize; NSRect windowFrameRect; - NSString *thePassword; - SPKeychain *keychain; // Work out whether a passphrase is being requested, extracting the key name NSString *keyName = [theQuery stringByMatching:@"^\\s*Enter passphrase for key \\'(.*)\\':\\s*$" capture:1L]; if (keyName) { [sshPasswordText setStringValue:[NSString stringWithFormat:@"Enter your password for the SSH key\n\"%@\"", keyName]]; [sshPasswordKeychainCheckbox setHidden:NO]; + currentKeyName = [keyName retain]; } else { [sshPasswordText setStringValue:theQuery]; - [sshPasswordKeychainCheckbox setHidden:YES]; + [sshPasswordKeychainCheckbox setHidden:YES]; + currentKeyName = nil; } // Request the password, sizing the window appropriately to fit the query @@ -544,45 +572,44 @@ windowFrameRect.size.height = ((queryTextSize.height < 40)?40:queryTextSize.height) + 140 + ([sshPasswordDialog isSheet]?0:22); [sshPasswordDialog setFrame:windowFrameRect display:NO]; [NSApp beginSheet:sshPasswordDialog modalForWindow:parentWindow modalDelegate:self didEndSelector:nil contextInfo:nil]; - NSInteger sshQueryResponseCode = [NSApp runModalForWindow:sshPasswordDialog]; - [NSApp endSheet:sshPasswordDialog]; - [sshPasswordDialog orderOut:nil]; - - switch (sshQueryResponseCode) { - - // OK - case 1: - thePassword = [NSString stringWithString:[sshPasswordField stringValue]]; - [sshPasswordField setStringValue:@""]; - if ([delegate respondsToSelector:@selector(setUndoManager:)] && [delegate undoManager]) { - [[delegate undoManager] removeAllActionsWithTarget:sshPasswordField]; - } else if ([[parentWindow windowController] document] && [[[parentWindow windowController] document] undoManager]) { - [[[[parentWindow windowController] document] undoManager] removeAllActionsWithTarget:sshPasswordField]; - } - requestedPassphrase = [[NSString alloc] initWithString:thePassword]; - - // Add to keychain if appropriate - if (keyName && [sshPasswordKeychainCheckbox state] == NSOnState) { - keychain = [[SPKeychain alloc] init]; - [keychain addPassword:thePassword forName:@"SSH" account:keyName withLabel:[NSString stringWithFormat:@"SSH: %@", keyName]]; - [keychain release]; - } - return; - - // Cancel - default: - return; - } } /* * Ends an existing modal session */ -- (IBAction) closeSheet:(id)sender +- (IBAction) closeSSHPasswordSheet:(id)sender { - [NSApp stopModalWithCode:[sender tag]]; + [answerAvailableCondition lock]; + requestedResponse = [sender tag]==1 ? YES : NO; + [NSApp endSheet:sshPasswordDialog]; + [sshPasswordDialog orderOut:nil]; + + if (requestedResponse) { + NSString *thePassword = [NSString stringWithString:[sshPasswordField stringValue]]; + [sshPasswordField setStringValue:@""]; + if ([delegate respondsToSelector:@selector(setUndoManager:)] && [delegate undoManager]) { + [[delegate undoManager] removeAllActionsWithTarget:sshPasswordField]; + } else if ([[parentWindow windowController] document] && [[[parentWindow windowController] document] undoManager]) { + [[[[parentWindow windowController] document] undoManager] removeAllActionsWithTarget:sshPasswordField]; + } + requestedPassphrase = [[NSString alloc] initWithString:thePassword]; + + // Add to keychain if appropriate + if (currentKeyName && [sshPasswordKeychainCheckbox state] == NSOnState) { + SPKeychain *keychain = [[SPKeychain alloc] init]; + [keychain addPassword:thePassword forName:@"SSH" account:currentKeyName withLabel:[NSString stringWithFormat:@"SSH: %@", currentKeyName]]; + [keychain release]; + [currentKeyName release]; + currentKeyName = nil; + } + } + + isAnswerAvailable = YES; + [answerAvailableCondition signal]; + [answerAvailableCondition unlock]; } + - (void)dealloc { delegate = nil; |