diff options
author | Kenny Root <kenny@the-b.org> | 2009-01-21 03:47:48 +0000 |
---|---|---|
committer | Kenny Root <kenny@the-b.org> | 2009-01-21 03:47:48 +0000 |
commit | 5be990cb0339abf90f35afe83f73726e801ebf7f (patch) | |
tree | 0abef3dc3d0b63d7a66c77f2c702b37b4e8053dc /src | |
parent | a5000c63527067254a0ce09ebf9c04934465b2f2 (diff) | |
download | connectbot-5be990cb0339abf90f35afe83f73726e801ebf7f.tar.gz connectbot-5be990cb0339abf90f35afe83f73726e801ebf7f.tar.bz2 connectbot-5be990cb0339abf90f35afe83f73726e801ebf7f.zip |
Allow PromptHelper to be preempted
* e.g., if a host disconnects during password authentication, it immediately closes the password prompt
Diffstat (limited to 'src')
-rw-r--r-- | src/org/connectbot/ConsoleActivity.java | 5 | ||||
-rw-r--r-- | src/org/connectbot/service/PromptHelper.java | 117 | ||||
-rw-r--r-- | src/org/connectbot/service/TerminalBridge.java | 26 |
3 files changed, 110 insertions, 38 deletions
diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java index 4485f5b..00b1543 100644 --- a/src/org/connectbot/ConsoleActivity.java +++ b/src/org/connectbot/ConsoleActivity.java @@ -780,9 +780,12 @@ public class ConsoleActivity extends Activity { protected void updatePromptVisible() { // check if our currently-visible terminalbridge is requesting any prompt services View view = findCurrentView(R.id.console_flip); + + // Hide all the prompts in case a prompt request was canceled + hideAllPrompts(); + if(!(view instanceof TerminalView)) { // we dont have an active view, so hide any prompts - hideAllPrompts(); return; } diff --git a/src/org/connectbot/service/PromptHelper.java b/src/org/connectbot/service/PromptHelper.java index 9b783bb..2fc5183 100644 --- a/src/org/connectbot/service/PromptHelper.java +++ b/src/org/connectbot/service/PromptHelper.java @@ -12,44 +12,51 @@ import android.os.Message; * @author jsharkey */ public class PromptHelper { - private final Object tag; + + private Handler handler = null; + + private Semaphore promptToken; + private Semaphore promptResponse; + + public String promptHint = null; + public Object promptRequested = null; + + private Object response = null; public PromptHelper(Object tag) { this.tag = tag; + + // Threads must acquire this before they can send a prompt. + promptToken = new Semaphore(1); + + // Responses will release this semaphore. + promptResponse = new Semaphore(0); } - private Handler handler = null; /** * Register a user interface handler, if available. */ - public synchronized void setHandler(Handler handler) { + public void setHandler(Handler handler) { this.handler = handler; } - - private Semaphore promptResponse = new Semaphore(0); - - public String promptHint = null; - public Object promptRequested = null; - - private Object response = null; /** * Set an incoming value from an above user interface. Will automatically * notify any waiting requests. */ public void setResponse(Object value) { - this.response = value; - this.promptResponse.release(); + response = value; + promptResponse.release(); } /** * Return the internal response value just before erasing and returning it. */ protected Object popResponse() { - Object value = this.response; - this.response = null; + Object value = response; + response = null; return value; } @@ -57,44 +64,98 @@ public class PromptHelper { /** * Request a prompt response from parent. This is a blocking call until user * interface returns a value. + * Only one thread can call this at a time. cancelPrompt() will force this to + * immediately return. */ - public synchronized Object requestPrompt(String hint, Object type) throws Exception { - this.promptHint = hint; - this.promptRequested = type; + private Object requestPrompt(String hint, Object type, boolean immediate) throws InterruptedException { + Object response = null; + + if (immediate) + cancelPrompt(); + + promptToken.acquire(); + + try { + promptHint = hint; + promptRequested = type; + + // notify any parent watching for live events + if (handler != null) + Message.obtain(handler, -1, tag).sendToTarget(); - // notify any parent watching for live events - if(handler != null) - Message.obtain(handler, -1, tag).sendToTarget(); + // acquire lock until user passes back value + promptResponse.acquire(); + promptRequested = null; + + response = popResponse(); + } finally { + promptToken.release(); + } - // acquire lock until user passes back value - this.promptResponse.acquire(); - this.promptRequested = null; - return this.popResponse(); + return response; } /** * Request a string response from parent. This is a blocking call until user * interface returns a value. + * @param hint prompt hint for user to answer + * @param immediate whether to cancel other in-progress prompts + * @return string user has entered */ - public String requestStringPrompt(String hint) { + public String requestStringPrompt(String hint, boolean immediate) { String value = null; try { - value = (String)this.requestPrompt(hint, String.class); + value = (String)this.requestPrompt(hint, String.class, immediate); } catch(Exception e) { } return value; } /** + * Convenience method for requestStringPrompt(String, boolean) + * @param hint prompt hint for user to answer + * @return string user has entered + */ + public String requestStringPrompt(String hint) { + return requestStringPrompt(hint, false); + } + + /** * Request a boolean response from parent. This is a blocking call until user * interface returns a value. + * @param hint prompt hint for user to answer + * @param immediate whether to cancel other in-progress prompts + * @return choice user has made (yes/no) */ - public Boolean requestBooleanPrompt(String hint) { + public Boolean requestBooleanPrompt(String hint, boolean immediate) { Boolean value = null; try { - value = (Boolean)this.requestPrompt(hint, Boolean.class); + value = (Boolean)this.requestPrompt(hint, Boolean.class, immediate); } catch(Exception e) { } return value; } + + /** + * Convenience method for requestBooleanPrompt(String, boolean) + * @param hint String to present to user in prompt + * @return choice user has made (yes/no) + */ + public Boolean requestBooleanPrompt(String hint) { + return requestBooleanPrompt(hint, false); + } + + /** + * Cancel an in-progress prompt. + */ + public void cancelPrompt() { + if (!promptToken.tryAcquire()) { + // A thread has the token, so try to interrupt it + response = null; + promptResponse.release(); + } else { + // No threads have acquired the token + promptToken.release(); + } + } } diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java index 8ffd729..8024c88 100644 --- a/src/org/connectbot/service/TerminalBridge.java +++ b/src/org/connectbot/service/TerminalBridge.java @@ -368,9 +368,14 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal } else { // otherwise load key from database and prompt for password as needed String password = null; - if (pubkey.isEncrypted()) + if (pubkey.isEncrypted()) { password = promptHelper.requestStringPrompt(String.format("Password for key '%s'", pubkey.getNickname())); - + + // Something must have interrupted the prompt. + if (password == null) + return false; + } + if(PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType())) { // load specific key using pem format trileadKey = PEMDecoder.decode(new String(pubkey.getPrivateKey()).toCharArray(), password); @@ -447,21 +452,24 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal break; } } - } else { - outputLine("Attempting 'publickey' authentication with a specific SSH key"); + outputLine("Attempting 'publickey' authentication with a specific public key"); // use a specific key for this host, as requested PubkeyBean pubkey = manager.pubkeydb.findPubkeyById(pubkeyId); - if (tryPublicKey(pubkey)) - finishConnection(); + if (pubkey == null) + outputLine("Selected public key is invalid, try reselecting key in host editor"); + else + if (tryPublicKey(pubkey)) + finishConnection(); } pubkeysExhausted = true; } else if (connection.isAuthMethodAvailable(host.getUsername(), AUTH_PASSWORD)) { outputLine("Attempting 'password' authentication"); String password = promptHelper.requestStringPrompt("Password"); - if(connection.authenticateWithPassword(host.getUsername(), password)) { + if (password != null + && connection.authenticateWithPassword(host.getUsername(), password)) { finishConnection(); } else { outputLine("Authentication method 'password' failed"); @@ -759,8 +767,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal } else { new Thread(new Runnable() { public void run() { - boolean result = promptHelper.requestBooleanPrompt("Host has disconnected.\nClose session?"); - if (result) { + Boolean result = promptHelper.requestBooleanPrompt("Host has disconnected.\nClose session?", true); + if (result == null || result.booleanValue()) { awaitingClose = true; // Tell the TerminalManager that we can be destroyed now. |