diff options
| -rw-r--r-- | res/xml/host_prefs.xml | 6 | ||||
| -rw-r--r-- | src/org/connectbot/ConsoleActivity.java | 39 | ||||
| -rw-r--r-- | src/org/connectbot/PortForwardListActivity.java | 25 | ||||
| -rw-r--r-- | src/org/connectbot/service/TerminalBridge.java | 93 | ||||
| -rw-r--r-- | src/org/connectbot/service/TerminalManager.java | 4 | ||||
| -rw-r--r-- | src/org/connectbot/util/HostDatabase.java | 42 | 
6 files changed, 168 insertions, 41 deletions
diff --git a/res/xml/host_prefs.xml b/res/xml/host_prefs.xml index 9669330..83aa6d6 100644 --- a/res/xml/host_prefs.xml +++ b/res/xml/host_prefs.xml @@ -49,6 +49,12 @@  		android:title="Post-login automation"  		android:summary="Commands to run on remote server once authenticated"  		/> +		 +	<CheckBoxPreference +		android:key="wantsession" +		android:title="Start shell session" +		android:summary="Disable this preference to only use port forwards." +		/>  	<PreferenceCategory  		android:title="Connection settings"> diff --git a/src/org/connectbot/ConsoleActivity.java b/src/org/connectbot/ConsoleActivity.java index 98ff46c..1204669 100644 --- a/src/org/connectbot/ConsoleActivity.java +++ b/src/org/connectbot/ConsoleActivity.java @@ -133,9 +133,14 @@ public class ConsoleActivity extends Activity {  			} -			// show the requested bridge if found, also fade out overlay -			flip.setDisplayedChild(requestedIndex); -			flip.getCurrentView().findViewById(R.id.terminal_overlay).startAnimation(fade_out); +			try { +				// show the requested bridge if found, also fade out overlay +				flip.setDisplayedChild(requestedIndex); +				flip.getCurrentView().findViewById(R.id.terminal_overlay).startAnimation(fade_out); +			} catch (NullPointerException npe) { +				Log.d(TAG, "View went away when we were about to display it", npe); +			} +			  			updatePromptVisible();  			updateEmptyVisible(); @@ -608,8 +613,11 @@ public class ConsoleActivity extends Activity {  		final View view = findCurrentView(R.id.console_flip);  		boolean activeTerminal = (view instanceof TerminalView);  		boolean authenticated = false; -		if(activeTerminal) -			authenticated = ((TerminalView)view).bridge.fullyConnected; +		boolean sessionOpen = false; +		if(activeTerminal) { +			authenticated = ((TerminalView) view).bridge.isAuthenticated(); +			sessionOpen = ((TerminalView)view).bridge.isSessionOpen(); +		}  		disconnect = menu.add(R.string.console_menu_disconnect);  		disconnect.setEnabled(activeTerminal); @@ -628,7 +636,7 @@ public class ConsoleActivity extends Activity {  		copy = menu.add(R.string.console_menu_copy);  		copy.setIcon(android.R.drawable.ic_menu_set_as); -		copy.setEnabled(activeTerminal && authenticated); +		copy.setEnabled(activeTerminal);  		copy.setOnMenuItemClickListener(new OnMenuItemClickListener() {  			public boolean onMenuItemClick(MenuItem item) {  				// mark as copying and reset any previous bounds @@ -661,7 +669,7 @@ public class ConsoleActivity extends Activity {  		portForward = menu.add(R.string.console_menu_portforwards);  		portForward.setIcon(android.R.drawable.ic_menu_manage); -		portForward.setEnabled(activeTerminal && authenticated); +		portForward.setEnabled(authenticated);  		portForward.setOnMenuItemClickListener(new OnMenuItemClickListener() {  			public boolean onMenuItemClick(MenuItem item) {  				Intent intent = new Intent(ConsoleActivity.this, PortForwardListActivity.class); @@ -673,7 +681,7 @@ public class ConsoleActivity extends Activity {  		resize = menu.add(R.string.console_menu_resize);  		resize.setIcon(android.R.drawable.ic_menu_crop); -		resize.setEnabled(activeTerminal && authenticated); +		resize.setEnabled(activeTerminal && sessionOpen);  		resize.setOnMenuItemClickListener(new OnMenuItemClickListener() {  			public boolean onMenuItemClick(MenuItem item) {  				final TerminalView terminal = (TerminalView)view; @@ -724,14 +732,17 @@ public class ConsoleActivity extends Activity {  		final View view = findCurrentView(R.id.console_flip);  		boolean activeTerminal = (view instanceof TerminalView);  		boolean authenticated = false; -		if(activeTerminal) -			authenticated = ((TerminalView)view).bridge.fullyConnected; - +		boolean sessionOpen = false; +		if (activeTerminal) { +			authenticated = ((TerminalView)view).bridge.isAuthenticated(); +			sessionOpen = ((TerminalView)view).bridge.isSessionOpen(); +		} +		  		disconnect.setEnabled(activeTerminal); -		copy.setEnabled(activeTerminal && authenticated); -		paste.setEnabled(clipboard.hasText() && activeTerminal && authenticated); +		copy.setEnabled(activeTerminal); +		paste.setEnabled(clipboard.hasText() && activeTerminal && sessionOpen);  		portForward.setEnabled(activeTerminal && authenticated); -		resize.setEnabled(activeTerminal && authenticated); +		resize.setEnabled(activeTerminal && sessionOpen);  		return true;  	} diff --git a/src/org/connectbot/PortForwardListActivity.java b/src/org/connectbot/PortForwardListActivity.java index c5d4cb5..e2097fa 100644 --- a/src/org/connectbot/PortForwardListActivity.java +++ b/src/org/connectbot/PortForwardListActivity.java @@ -168,7 +168,18 @@ public class PortForwardListActivity extends ListActivity {  			public boolean onMenuItemClick(MenuItem item) {  				// build dialog to prompt user about updating  				final View portForwardView = inflater.inflate(R.layout.dia_portforward, null, false); +				final EditText destEdit = (EditText) portForwardView.findViewById(R.id.portforward_destination);  				final Spinner typeSpinner = (Spinner)portForwardView.findViewById(R.id.portforward_type); +				 +				typeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { +					public void onItemSelected(AdapterView<?> value, View view, +							int position, long id) { +						destEdit.setEnabled(position != 2); +					} +					public void onNothingSelected(AdapterView<?> arg0) {						 +					}	 +				}); +				  				new AlertDialog.Builder(PortForwardListActivity.this)  					.setView(portForwardView)  					.setPositiveButton(R.string.portforward_pos, new DialogInterface.OnClickListener() { @@ -176,9 +187,19 @@ public class PortForwardListActivity extends ListActivity {  							try {  								final EditText nicknameEdit = (EditText) portForwardView.findViewById(R.id.nickname);  								final EditText sourcePortEdit = (EditText) portForwardView.findViewById(R.id.portforward_source); -								final EditText destEdit = (EditText) portForwardView.findViewById(R.id.portforward_destination); -								String type = (String)typeSpinner.getSelectedItem(); +								String type = HostDatabase.PORTFORWARD_LOCAL; +								switch (typeSpinner.getSelectedItemPosition()) { +								case 0: +									type = HostDatabase.PORTFORWARD_LOCAL; +									break; +								case 1: +									type = HostDatabase.PORTFORWARD_REMOTE; +									break; +								case 2: +									type = HostDatabase.PORTFORWARD_DYNAMIC5; +									break; +								}  								PortForwardBean pfb = new PortForwardBean(hostId,  										nicknameEdit.getText().toString(), type, diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java index 1762262..4cb1b2b 100644 --- a/src/org/connectbot/service/TerminalBridge.java +++ b/src/org/connectbot/service/TerminalBridge.java @@ -109,6 +109,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  	public final String nickname;  	protected final String username;  	public String postlogin = null; +	private boolean wantSession = true;  	public final Connection connection;  	protected Session session; @@ -145,6 +146,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  			// read in all known hosts from hostdb  			KnownHosts hosts = manager.hostdb.getKnownHosts(); +			Boolean result;  			switch(hosts.verifyHostkey(hostname, serverHostKeyAlgorithm, serverHostKey)) {  			case KnownHosts.HOSTKEY_IS_OK: @@ -154,9 +156,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  				// prompt user  				outputLine(String.format("The authenticity of host '%s' can't be established.", hostname));  				outputLine(String.format("RSA key fingerprint is %s", KnownHosts.createHexFingerprint(serverHostKeyAlgorithm, serverHostKey))); -				//outputLine("[For now we'll assume you accept this key, but tap Menu and Disconnect if not.]"); -				//outputLine("Are you sure you want to continue connecting (yes/no)? "); -				Boolean result = promptHelper.requestBooleanPrompt("Are you sure you want\nto continue connecting?"); + +				result = promptHelper.requestBooleanPrompt("Are you sure you want\nto continue connecting?");  				if(result == null) return false;  				if(result.booleanValue()) {  					// save this key in known database @@ -172,9 +173,15 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  				outputLine("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");  				outputLine("It is also possible that the RSA host key has just been changed.");  				outputLine(String.format("RSA key fingerprint is %s", KnownHosts.createHexFingerprint(serverHostKeyAlgorithm, serverHostKey))); -				outputLine("Host key verification failed."); -				return false; +				// Users have no way to delete keys, so we'll prompt them for now. +				result = promptHelper.requestBooleanPrompt("Are you sure you want\nto continue connecting?"); +				if(result == null) return false; +				if(result.booleanValue()) { +					// save this key in known database +					manager.hostdb.saveKnownHost(hostname, serverHostKeyAlgorithm, serverHostKey); +				} +				return result.booleanValue();				  			}  			return false; @@ -184,7 +191,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  	}  	public PromptHelper promptHelper; -	 +  	/**  	 * Create new terminal bridge with following parameters. We will immediately  	 * launch thread to start SSH connection and handle any hostkey verification @@ -199,6 +206,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  		this.emulation = manager.getEmulation();  		this.scrollback = manager.getScrollback();  		this.postlogin = manager.getPostLogin(nickname); +		this.wantSession = manager.getWantSession(nickname);  		// create prompt helper to relay password and hostkey requests up to gui  		this.promptHelper = new PromptHelper(this); @@ -260,7 +268,12 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  			public void run() {  				try {  					connection.connect(new HostKeyVerifier()); -					 +				} catch (IOException e) { +					Log.e(TAG, "Problem in SSH connection thread during authentication", e); +					Log.d(TAG, String.format("Cause is: %s", e.getCause().toString())); +				} +				 +				try {	  					// enter a loop to keep trying until authentication  					int tries = 0;  					while(!connection.isAuthenticationComplete() && tries++ < AUTH_TRIES && !disconnectFlag) { @@ -270,7 +283,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  						Thread.sleep(1000);  					}  				} catch(Exception e) { -					Log.e(TAG, "Problem in SSH connection thread", e); +					Log.e(TAG, "Problem in SSH connection thread during authentication", e);  				}  			}   		}).start(); @@ -466,13 +479,30 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  		}).start();  	} -	public boolean fullyConnected = false; +	private boolean authenticated = false; +	private boolean sessionOpen = false;  	/**  	 * Internal method to request actual PTY terminal once we've finished  	 * authentication. If called before authenticated, it will just fail.  	 */  	protected void finishConnection() { +		setAuthenticated(true); +		 +		// Start up predefined port forwards +		for (PortForwardBean pfb : portForwards) { +			try { +				enablePortForward(pfb); +				outputLine(String.format("Enable port forward: %s", pfb.getDescription())); +			} catch (Exception e) { +				Log.e(TAG, "Error setting up port forward during connect", e); +			} +		} +		 +		if (!wantSession) { +			outputLine("Session will not be started due to host preference."); +			return; +		}  		try {  			this.session = connection.openSession(); @@ -508,21 +538,15 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  					}  				}  			}); -			this.relay.start(); +			relay.start();  			// force font-size to make sure we resizePTY as needed -			this.setFontSize(this.fontSize); +			setFontSize(this.fontSize); -			this.fullyConnected = true; -			 -			// Start up predefined port forwards -			for (PortForwardBean pfb : portForwards) { -				enablePortForward(pfb); -				Log.d(TAG, String.format("Enabling port formard %s (enabled? %b)", pfb.getDescription(), pfb.isEnabled())); -			} +			setSessionOpen(true);  			// finally send any post-login string, if requested -			this.injectString(postlogin); +			injectString(postlogin);  		} catch (IOException e1) {  			Log.e(TAG, "Problem while trying to create PTY in finishConnection()", e1); @@ -530,6 +554,20 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  	} +	/** +	 * @param sessionOpen the sessionOpen to set +	 */ +	public void setSessionOpen(boolean sessionOpen) { +		this.sessionOpen = sessionOpen; +	} + +	/** +	 * @return the sessionOpen +	 */ +	public boolean isSessionOpen() { +		return sessionOpen; +	} +  	protected BridgeDisconnectedListener disconnectListener = null;  	public void setOnDisconnectedListener(BridgeDisconnectedListener disconnectListener) { @@ -553,7 +591,8 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  		}).start();  		this.disconnectFlag = true; -		this.fullyConnected = false; +		this.authenticated = false; +		this.sessionOpen = false;  		// pass notification back up to terminal manager  		// the manager will do any gui notification if applicable @@ -1145,4 +1184,18 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener, InteractiveCal  			return false;  		}  	} + +	/** +	 * @param authenticated the authenticated to set +	 */ +	public void setAuthenticated(boolean authenticated) { +		this.authenticated = authenticated; +	} + +	/** +	 * @return the authenticated +	 */ +	public boolean isAuthenticated() { +		return authenticated; +	}  } diff --git a/src/org/connectbot/service/TerminalManager.java b/src/org/connectbot/service/TerminalManager.java index 336d1fa..a0753df 100644 --- a/src/org/connectbot/service/TerminalManager.java +++ b/src/org/connectbot/service/TerminalManager.java @@ -167,6 +167,10 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen  		return hostdb.getPostLogin(nickname);  	} +	public boolean getWantSession(String nickname) { +		return hostdb.getWantSession(nickname); +	} +  	public String getKeyMode() {  		return prefs.getString(this.pref_keymode, getString(R.string.list_keymode_right)); // "Use right-side keys"  	} diff --git a/src/org/connectbot/util/HostDatabase.java b/src/org/connectbot/util/HostDatabase.java index dd003fe..c98fcce 100644 --- a/src/org/connectbot/util/HostDatabase.java +++ b/src/org/connectbot/util/HostDatabase.java @@ -43,7 +43,7 @@ public class HostDatabase extends SQLiteOpenHelper {  	public final static String TAG = HostDatabase.class.toString();  	public final static String DB_NAME = "hosts"; -	public final static int DB_VERSION = 12; +	public final static int DB_VERSION = 13;  	public final static String TABLE_HOSTS = "hosts";  	public final static String FIELD_HOST_NICKNAME = "nickname"; @@ -57,6 +57,7 @@ public class HostDatabase extends SQLiteOpenHelper {  	public final static String FIELD_HOST_USEKEYS = "usekeys";  	public final static String FIELD_HOST_POSTLOGIN = "postlogin";  	public final static String FIELD_HOST_PUBKEYID = "pubkeyid"; +	public final static String FIELD_HOST_WANTSESSION = "wantsession";  	public final static String TABLE_PORTFORWARDS = "portforwards";  	public final static String FIELD_PORTFORWARD_HOSTID = "hostid"; @@ -97,7 +98,8 @@ public class HostDatabase extends SQLiteOpenHelper {  				+ FIELD_HOST_COLOR + " TEXT, "  				+ FIELD_HOST_USEKEYS + " TEXT, "  				+ FIELD_HOST_POSTLOGIN + " TEXT, " -				+ FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY + ")"); +				+ FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY + ", " +				+ FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "')");  		// insert a few sample hosts, none of which probably connect  		//this.createHost(db, "connectbot@bravo", "connectbot", "192.168.254.230", 22, COLOR_GRAY); @@ -136,7 +138,10 @@ public class HostDatabase extends SQLiteOpenHelper {  					+ FIELD_PORTFORWARD_TYPE + " TEXT NOT NULL DEFAULT " + PORTFORWARD_LOCAL + ", "  					+ FIELD_PORTFORWARD_SOURCEPORT + " INTEGER NOT NULL DEFAULT 8080, "  					+ FIELD_PORTFORWARD_DESTADDR + " TEXT, " -					+ FIELD_PORTFORWARD_DESTPORT + " INTEGER)");			 +					+ FIELD_PORTFORWARD_DESTPORT + " INTEGER)"); +		case 12: +			db.execSQL("ALTER TABLE " + TABLE_HOSTS +					+ " ADD COLUMN " + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "'");  		}  	} @@ -219,6 +224,7 @@ public class HostDatabase extends SQLiteOpenHelper {  		if(color != null)  			values.put(FIELD_HOST_COLOR, color);  		values.put(FIELD_HOST_PUBKEYID, pubkeyId); +		values.put(FIELD_HOST_WANTSESSION, Boolean.toString(true));  		return db.insert(TABLE_HOSTS, null, values); @@ -254,19 +260,45 @@ public class HostDatabase extends SQLiteOpenHelper {  	 * Find the post-login command string for the given nickname.  	 */  	public String getPostLogin(String nickname) { -		  		String result = null; +		  		SQLiteDatabase db = this.getReadableDatabase();  		Cursor c = db.query(TABLE_HOSTS, new String[] { FIELD_HOST_POSTLOGIN },  				FIELD_HOST_NICKNAME + " = ?", new String[] { nickname }, null, null, null); -		if(c == null || !c.moveToFirst()) { +		 +		if (c == null || !c.moveToFirst()) {  			result = null;  		} else {  			result = c.getString(c.getColumnIndexOrThrow(FIELD_HOST_POSTLOGIN));  		} +		c.close(); +		db.close(); +		  		return result; +	} + +	/** +	 * Check whether a host should have a shell session started. +	 * @param nickname Nick name of host to check +	 * @return true if host should have a shell session started +	 */ +	public boolean getWantSession(String nickname) { +		Boolean result = true; +		SQLiteDatabase db = this.getReadableDatabase(); +		Cursor c = db.query(TABLE_HOSTS, new String[] { FIELD_HOST_WANTSESSION }, +				FIELD_HOST_NICKNAME + " = ?", new String[] { nickname }, null, null, null); +		if(c == null || !c.moveToFirst()) { +			result = true; +		} else { +			result = Boolean.valueOf(c.getString(c.getColumnIndexOrThrow(FIELD_HOST_WANTSESSION))); +		} +		 +		c.close(); +		db.close(); +		 +		return result;  	}  	/**  | 
