aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2009-01-21 03:47:48 +0000
committerKenny Root <kenny@the-b.org>2009-01-21 03:47:48 +0000
commit5be990cb0339abf90f35afe83f73726e801ebf7f (patch)
tree0abef3dc3d0b63d7a66c77f2c702b37b4e8053dc /src
parenta5000c63527067254a0ce09ebf9c04934465b2f2 (diff)
downloadconnectbot-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.java5
-rw-r--r--src/org/connectbot/service/PromptHelper.java117
-rw-r--r--src/org/connectbot/service/TerminalBridge.java26
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.