diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/org/connectbot/ConsoleActivity.java | 114 | ||||
-rw-r--r-- | src/org/connectbot/HostEditorActivity.java | 1 | ||||
-rw-r--r-- | src/org/connectbot/HostListActivity.java | 12 | ||||
-rw-r--r-- | src/org/connectbot/R.java | 22 | ||||
-rw-r--r-- | src/org/connectbot/service/TerminalBridge.java | 133 | ||||
-rw-r--r-- | src/org/connectbot/service/TerminalManager.java | 3 |
6 files changed, 167 insertions, 118 deletions
diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java index b97669e..34cc83a 100644 --- a/src/org/connectbot/ConsoleActivity.java +++ b/src/org/connectbot/ConsoleActivity.java @@ -18,21 +18,27 @@ package org.connectbot; +import java.util.regex.Pattern; + import org.connectbot.service.PromptHelper; import org.connectbot.service.TerminalBridge; import org.connectbot.service.TerminalManager; import android.app.Activity; +import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.ServiceConnection; +import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.PowerManager; +import android.preference.PreferenceManager; import android.text.ClipboardManager; import android.util.Log; import android.view.GestureDetector; @@ -52,8 +58,10 @@ import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.Button; import android.widget.EditText; +import android.widget.RadioButton; import android.widget.RelativeLayout; import android.widget.TextView; +import android.widget.Toast; import android.widget.ViewFlipper; import de.mud.terminal.vt320; @@ -243,8 +251,11 @@ public class ConsoleActivity extends Activity { bound.defaultBridge = terminal.bridge; } - protected PowerManager.WakeLock wakelock; - + protected SharedPreferences prefs = null; + protected PowerManager.WakeLock wakelock = null; + + protected String PREF_KEEPALIVE = null; + @Override public void onStart() { super.onStart(); @@ -255,7 +266,7 @@ public class ConsoleActivity extends Activity { // make sure we dont let the screen fall asleep // this also keeps the wifi chipset from disconnecting us - if (this.wakelock != null) + if(this.wakelock != null && prefs.getBoolean(PREF_KEEPALIVE, true)) wakelock.acquire(); } @@ -266,7 +277,7 @@ public class ConsoleActivity extends Activity { this.unbindService(connection); // allow the screen to dim and fall asleep - if (this.wakelock != null) + if(this.wakelock != null) wakelock.release(); } @@ -302,9 +313,12 @@ public class ConsoleActivity extends Activity { this.setContentView(R.layout.act_console); this.clipboard = (ClipboardManager)this.getSystemService(CLIPBOARD_SERVICE); + this.prefs = PreferenceManager.getDefaultSharedPreferences(this); PowerManager manager = (PowerManager)getSystemService(Context.POWER_SERVICE); wakelock = manager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG); + + this.PREF_KEEPALIVE = this.getResources().getString(R.string.pref_keepalive); // handle requested console from incoming intent this.requested = this.getIntent().getData(); @@ -504,19 +518,24 @@ public class ConsoleActivity extends Activity { } - protected MenuItem copy, paste; + protected MenuItem disconnect, copy, paste, tunnel; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - MenuItem add = menu.add("Disconnect"); - add.setIcon(android.R.drawable.ic_menu_close_clear_cancel); - add.setOnMenuItemClickListener(new OnMenuItemClickListener() { + final View view = findCurrentView(R.id.console_flip); + boolean activeTerminal = (view instanceof TerminalView); + boolean authenticated = false; + if(activeTerminal) + authenticated = ((TerminalView)view).bridge.connection.isAuthenticationComplete(); + + disconnect = menu.add("Disconnect"); + disconnect.setEnabled(activeTerminal); + disconnect.setIcon(android.R.drawable.ic_menu_close_clear_cancel); + disconnect.setOnMenuItemClickListener(new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { // close the currently visible session - View view = findCurrentView(R.id.console_flip); - if(view == null) return false; TerminalView terminal = (TerminalView)view; bound.disconnect(terminal.bridge); // movement should now be happening over in onDisconnect() handler @@ -528,18 +547,16 @@ public class ConsoleActivity extends Activity { copy = menu.add("Copy"); copy.setIcon(android.R.drawable.ic_menu_set_as); - copy.setEnabled(false); + copy.setEnabled(false && activeTerminal && authenticated); // TODO: freeze current console, allow selection, and set clipboard to contents paste = menu.add("Paste"); paste.setIcon(android.R.drawable.ic_menu_edit); - paste.setEnabled(clipboard.hasText()); + paste.setEnabled(clipboard.hasText() && activeTerminal && authenticated); paste.setOnMenuItemClickListener(new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { // force insert of clipboard text into current console - View view = findCurrentView(R.id.console_flip); - if(view == null) return false; TerminalView terminal = (TerminalView)view; // pull string from clipboard and generate all events to force down @@ -549,16 +566,83 @@ public class ConsoleActivity extends Activity { return true; } }); + + + tunnel = menu.add("Tunnel"); + tunnel.setIcon(android.R.drawable.ic_menu_manage); + tunnel.setEnabled(activeTerminal && authenticated); + tunnel.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + // show dialog to create tunnel for this host + final TerminalView terminal = (TerminalView)view; + + // build dialog to prompt user about updating + final View tunnelView = inflater.inflate(R.layout.dia_tunnel, null, false); + ((RadioButton)tunnelView.findViewById(R.id.tunnel_local)).setChecked(true); + new AlertDialog.Builder(ConsoleActivity.this) + .setView(tunnelView) + .setPositiveButton("Create tunnel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + String type = ((RadioButton)tunnelView.findViewById(R.id.tunnel_local)).isChecked() ? TUNNEL_LOCAL : TUNNEL_REMOTE; + String source = ((TextView)tunnelView.findViewById(R.id.tunnel_source)).getText().toString(); + String dest = ((TextView)tunnelView.findViewById(R.id.tunnel_destination)).getText().toString(); + + createTunnel(terminal, type, source, dest); + } + }) + .setNegativeButton("Cancel", null).create().show(); + + return true; + } + }); return true; } + + public final static String EXTRA_TYPE = "type", EXTRA_SOURCE = "source", EXTRA_DEST = "dest", EXTRA_SILENT = "silent"; + public final static String TUNNEL_LOCAL = "local", TUNNEL_REMOTE = "remote"; + + protected void createTunnel(TerminalView target, String type, String source, String dest) { + String summary = null; + try { + boolean local = TUNNEL_LOCAL.equals(type); + int sourcePort = Integer.parseInt(source); + String[] destSplit = dest.split(":"); + String destHost = destSplit[0]; + int destPort = Integer.parseInt(destSplit[1]); + + if(local) { + target.bridge.connection.createLocalPortForwarder(sourcePort, destHost, destPort); + summary = String.format("Successfully created tunnel -L%d:%s:%d", sourcePort, destHost, destPort); + } else { + target.bridge.connection.requestRemotePortForwarding("", sourcePort, destHost, destPort); + summary = String.format("Successfully created tunnel -R%d:%s:%d", sourcePort, destHost, destPort); + } + } catch(Exception e) { + Log.e(TAG, "Problem trying to create tunnel", e); + summary = "Problem creating tunnel, maybe you're using ports under 1024?"; + } + + Toast.makeText(ConsoleActivity.this, summary, Toast.LENGTH_LONG).show(); + + } + @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - paste.setEnabled(clipboard.hasText()); + final View view = findCurrentView(R.id.console_flip); + boolean activeTerminal = (view instanceof TerminalView); + boolean authenticated = false; + if(activeTerminal) + authenticated = ((TerminalView)view).bridge.connection.isAuthenticationComplete(); + + disconnect.setEnabled(activeTerminal); + copy.setEnabled(false && activeTerminal && authenticated); + paste.setEnabled(clipboard.hasText() && activeTerminal && authenticated); + tunnel.setEnabled(activeTerminal && authenticated); return true; } diff --git a/src/org/connectbot/HostEditorActivity.java b/src/org/connectbot/HostEditorActivity.java index 86a517c..84e0790 100644 --- a/src/org/connectbot/HostEditorActivity.java +++ b/src/org/connectbot/HostEditorActivity.java @@ -67,6 +67,7 @@ public class HostEditorActivity extends PreferenceActivity implements OnSharedPr for(int i = 0; i < cursor.getColumnCount(); i++) { String key = cursor.getColumnName(i); + if(key.equals(HostDatabase.FIELD_HOST_HOSTKEY)) continue; String value = cursor.getString(i); values.put(key, value); } diff --git a/src/org/connectbot/HostListActivity.java b/src/org/connectbot/HostListActivity.java index 9cf1063..6581b59 100644 --- a/src/org/connectbot/HostListActivity.java +++ b/src/org/connectbot/HostListActivity.java @@ -90,11 +90,14 @@ public class HostListActivity extends ListActivity { @Override public void onStart() { super.onStart(); - + // start the terminal manager service this.startService(new Intent(this, TerminalManager.class)); this.bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE); - + + if(this.hostdb == null) + this.hostdb = new HostDatabase(this); + this.updateCursor(); } @@ -109,6 +112,11 @@ public class HostListActivity extends ListActivity { this.hosts = null; } + if(this.hostdb != null) { + this.hostdb.close(); + this.hostdb = null; + } + } diff --git a/src/org/connectbot/R.java b/src/org/connectbot/R.java index 85662bb..2e6c118 100644 --- a/src/org/connectbot/R.java +++ b/src/org/connectbot/R.java @@ -47,25 +47,30 @@ public final class R { public static final int console_prompt_no=0x7f090003; public static final int console_prompt_yes=0x7f090004; public static final int front_quickconnect=0x7f090005; - public static final int terminal_overlay=0x7f090009; + public static final int terminal_overlay=0x7f09000d; + public static final int tunnel_destination=0x7f09000c; + public static final int tunnel_local=0x7f090009; + public static final int tunnel_remote=0x7f09000a; + public static final int tunnel_source=0x7f09000b; public static final int wizard_flipper=0x7f090006; } public static final class layout { public static final int act_console=0x7f030000; public static final int act_hostlist=0x7f030001; public static final int act_wizard=0x7f030002; - public static final int item_host=0x7f030003; - public static final int item_terminal=0x7f030004; - public static final int wiz_eula=0x7f030005; - public static final int wiz_features=0x7f030006; + public static final int dia_tunnel=0x7f030003; + public static final int item_host=0x7f030004; + public static final int item_terminal=0x7f030005; + public static final int wiz_eula=0x7f030006; + public static final int wiz_features=0x7f030007; } public static final class string { public static final int alert_disconnect_msg=0x7f070015; public static final int app_desc=0x7f070001; public static final int app_name=0x7f070000; - public static final int bind_days=0x7f07001c; - public static final int bind_hours=0x7f07001b; - public static final int bind_minutes=0x7f07001a; + public static final int bind_days=0x7f07001d; + public static final int bind_hours=0x7f07001c; + public static final int bind_minutes=0x7f07001b; public static final int button_add=0x7f070011; public static final int button_cancel=0x7f070012; public static final int button_change=0x7f070013; @@ -79,6 +84,7 @@ public final class R { public static final int msg_copyright=0x7f070016; public static final int msg_version=0x7f070017; public static final int pref_emulation=0x7f070018; + public static final int pref_keepalive=0x7f07001a; public static final int pref_scrollback=0x7f070019; public static final int prompt_touch=0x7f07000f; public static final int resolve_connect=0x7f070009; diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java index 3fe73f0..45cc7cb 100644 --- a/src/org/connectbot/service/TerminalBridge.java +++ b/src/org/connectbot/service/TerminalBridge.java @@ -97,7 +97,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal protected final String username; public String postlogin = null; - protected final Connection connection; + public final Connection connection; protected Session session; protected final Paint defaultPaint; @@ -226,6 +226,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal } + public final static int AUTH_TRIES = 20; + /** * Spawn thread to open connection and start login process. */ @@ -236,7 +238,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal connection.connect(new HostKeyVerifier()); // enter a loop to keep trying until authentication - while(!connection.isAuthenticationComplete()) { + int tries = 0; + while(!connection.isAuthenticationComplete() && tries++ < AUTH_TRIES && !disconnectFlag) { handleAuthentication(); // sleep to make sure we dont kill system @@ -307,43 +310,6 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal this.redraw(); } -// public Handler parentHandler = null; -// -// public boolean promptRequested = false; -// public String promptHint = null; -// -// protected void requestPromptVisible(boolean visible, String hint) { -// this.promptRequested = visible; -// this.promptHint = hint; -// -// // pass notification up to any attached gui -// if(this.parentHandler != null) -// Message.obtain(this.parentHandler, ConsoleActivity.HANDLE_PROMPT, this).sendToTarget(); -// } - -// /** -// * Attempt to try password authentication using given string. -// */ -// public void incomingPassword(String password) { -// try { -// if (currentMethod == AUTH_PASSWORD) { -// Log.d(TAG, "Attempting to try password authentication"); -// if (this.connection.authenticateWithPassword(this.username, password)) { -// requestPromptVisible(false, null); -// finishConnection(); -// return; -// } -// } else if (currentMethod == AUTH_KEYBOARDINTERACTIVE) { -// Log.d(TAG, "Attempting to try keyboard-interactive authentication"); -// currentChallengeResponse = password; -// waitChallengeResponse.release(); -// } -// } catch (IOException e) { -// Log.e(TAG, "Problem while trying to authenticate with password", e); -// } -// this.outputLine("Permission denied, please try again."); -// } - /** * Inject a specific string into this terminal. Used for post-login strings * and pasting clipboard. @@ -416,6 +382,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal this.disconnectListener = disconnectListener; } + protected boolean disconnectFlag = false; + /** * Force disconnection of this terminal bridge. */ @@ -430,6 +398,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal } }).start(); + this.disconnectFlag = true; + // pass notification back up to terminal manager // the manager will do any gui notification if applicable if(this.disconnectListener != null) @@ -439,12 +409,6 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal public KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD); -// /** -// * Buffer of collected characters, for example when prompted for password or -// * accepting a hostkey. -// */ -// //protected StringBuffer collected = new StringBuffer(); - /** * Handle onKey() events coming down from a {@link TerminalView} above us. * We might collect these for our internal buffer when working with hostkeys @@ -469,56 +433,41 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal boolean printing = (keymap.isPrintingKey(keyCode) || keyCode == KeyEvent.KEYCODE_SPACE); - if(this.session == null) { - // check to see if we are collecting password information -// if(keyCode == KeyEvent.KEYCODE_ENTER) { -// this.incomingPassword(collected.toString()); -// collected = new StringBuffer(); -// return true; -// } else if(printing) { -// collected.appendCodePoint(keymap.get(keyCode, event.getMetaState())); -// return true; -// } else if(keyCode == KeyEvent.KEYCODE_DEL && collected.length() > 0) { -// collected.deleteCharAt(collected.length() - 1); -// return true; -// } - - } else { + // skip keys if we arent connected yet + if(this.session == null) return false; - // otherwise pass through to existing session - // print normal keys - if (printing) { - int key = keymap.get(keyCode, event.getMetaState()); + // otherwise pass through to existing session + // print normal keys + if (printing) { + int key = keymap.get(keyCode, event.getMetaState()); + if (ctrlPressed) { + // Support CTRL-A through CTRL-Z + if (key >= 0x61 && key <= 0x79) + key -= 0x60; + else if (key >= 0x40 && key <= 0x59) + key -= 0x39; + ctrlPressed = false; + } + this.stdin.write(key); + return true; + } + + // look for special chars + switch(keyCode) { + case KeyEvent.KEYCODE_DEL: stdin.write(0x08); return true; + case KeyEvent.KEYCODE_ENTER: ((vt320)buffer).keyTyped(vt320.KEY_ENTER, ' ', event.getMetaState()); return true; + case KeyEvent.KEYCODE_DPAD_LEFT: ((vt320)buffer).keyPressed(vt320.KEY_LEFT, ' ', event.getMetaState()); return true; + case KeyEvent.KEYCODE_DPAD_UP: ((vt320)buffer).keyPressed(vt320.KEY_UP, ' ', event.getMetaState()); return true; + case KeyEvent.KEYCODE_DPAD_DOWN: ((vt320)buffer).keyPressed(vt320.KEY_DOWN, ' ', event.getMetaState()); return true; + case KeyEvent.KEYCODE_DPAD_RIGHT: ((vt320)buffer).keyPressed(vt320.KEY_RIGHT, ' ', event.getMetaState()); return true; + case KeyEvent.KEYCODE_DPAD_CENTER: + // TODO: Add some visual indication of Ctrl state if (ctrlPressed) { - // Support CTRL-A through CTRL-Z - if (key >= 0x61 && key <= 0x79) - key -= 0x60; - else if (key >= 0x40 && key <= 0x59) - key -= 0x39; - ctrlPressed = false; - } - this.stdin.write(key); + stdin.write(0x1B); // ESC + ctrlPressed = false; + } else + ctrlPressed = true; return true; - } - - // look for special chars - switch(keyCode) { - case KeyEvent.KEYCODE_DEL: stdin.write(0x08); return true; - case KeyEvent.KEYCODE_ENTER: ((vt320)buffer).keyTyped(vt320.KEY_ENTER, ' ', event.getMetaState()); return true; - case KeyEvent.KEYCODE_DPAD_LEFT: ((vt320)buffer).keyPressed(vt320.KEY_LEFT, ' ', event.getMetaState()); return true; - case KeyEvent.KEYCODE_DPAD_UP: ((vt320)buffer).keyPressed(vt320.KEY_UP, ' ', event.getMetaState()); return true; - case KeyEvent.KEYCODE_DPAD_DOWN: ((vt320)buffer).keyPressed(vt320.KEY_DOWN, ' ', event.getMetaState()); return true; - case KeyEvent.KEYCODE_DPAD_RIGHT: ((vt320)buffer).keyPressed(vt320.KEY_RIGHT, ' ', event.getMetaState()); return true; - case KeyEvent.KEYCODE_DPAD_CENTER: - // TODO: Add some visual indication of Ctrl state - if (ctrlPressed) { - stdin.write(0x1B); // ESC - ctrlPressed = false; - } else - ctrlPressed = true; - return true; - } - } } catch (IOException e) { diff --git a/src/org/connectbot/service/TerminalManager.java b/src/org/connectbot/service/TerminalManager.java index de98eda..1941f8b 100644 --- a/src/org/connectbot/service/TerminalManager.java +++ b/src/org/connectbot/service/TerminalManager.java @@ -102,6 +102,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen TerminalBridge bridge = new TerminalBridge(hostdb, nickname, username, hostname, port, emulation, scrollback); bridge.disconnectListener = this; bridge.postlogin = postlogin; + bridge.setOnDisconnectedListener(this); bridge.startConnection(); this.bridges.add(bridge); @@ -150,7 +151,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen * internal list of active connections. */ public void disconnect(TerminalBridge bridge) { - // we will be notified about this through call back up to disconnected() + // we will be notified about this through call back up to onDisconnected() bridge.disconnect(); } |