aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJeffrey Sharkey <jsharkey@jsharkey.org>2008-10-24 21:05:14 +0000
committerJeffrey Sharkey <jsharkey@jsharkey.org>2008-10-24 21:05:14 +0000
commit6a17ff8094a9a651ee86fc26a63bcdf91254d6d0 (patch)
tree9aedf687801ec1b8f9c35713ea145e8a085b4fdb /src
parentbbd2518841228d37b57b10e2eafdd700bbdf8509 (diff)
downloadconnectbot-6a17ff8094a9a651ee86fc26a63bcdf91254d6d0.tar.gz
connectbot-6a17ff8094a9a651ee86fc26a63bcdf91254d6d0.tar.bz2
connectbot-6a17ff8094a9a651ee86fc26a63bcdf91254d6d0.zip
* removed older code to clean stuff up
* renamed some classes to make clearer * added javadoc everywhere to help explain stuff * separated private key db from host db * removed older "surface" bridge/view because they are painfully slow on hardware, didnt speed up things like we expected they would because lock/unlock of accelerated surface is expensive
Diffstat (limited to 'src')
-rw-r--r--src/org/connectbot/AboutActivity.java17
-rw-r--r--src/org/connectbot/ConsoleActivity.java (renamed from src/org/connectbot/Console.java)80
-rw-r--r--src/org/connectbot/FrontPage.java133
-rw-r--r--src/org/connectbot/HostEditorActivity.java (renamed from src/org/connectbot/HostEditor.java)20
-rw-r--r--src/org/connectbot/HostListActivity.java (renamed from src/org/connectbot/HostList.java)149
-rw-r--r--src/org/connectbot/R.java67
-rw-r--r--src/org/connectbot/SettingsActivity.java20
-rw-r--r--src/org/connectbot/TerminalView.java56
-rw-r--r--src/org/connectbot/TerminalViewSurface.java37
-rw-r--r--src/org/connectbot/WizardActivity.java24
-rw-r--r--src/org/connectbot/service/TerminalBridge.java233
-rw-r--r--src/org/connectbot/service/TerminalBridgeSurface.java310
-rw-r--r--src/org/connectbot/service/TerminalManager.java101
-rw-r--r--src/org/connectbot/util/HostBinder.java47
-rw-r--r--src/org/connectbot/util/HostDatabase.java53
-rw-r--r--src/org/connectbot/util/KeyDatabase.java65
-rw-r--r--src/org/connectbot/util/UpdateHelper.java185
-rw-r--r--src/org/theb/provider/HostDb.java40
-rw-r--r--src/org/theb/ssh/ConnectionThread.java30
-rw-r--r--src/org/theb/ssh/FeedbackUI.java25
-rw-r--r--src/org/theb/ssh/HostDbProvider.java257
-rw-r--r--src/org/theb/ssh/HostEditor.java177
-rw-r--r--src/org/theb/ssh/HostsList.java406
-rw-r--r--src/org/theb/ssh/InteractiveHostKeyVerifier.java32
-rw-r--r--src/org/theb/ssh/JCTerminalView.java330
-rw-r--r--src/org/theb/ssh/JTATerminalView.java375
-rw-r--r--src/org/theb/ssh/PasswordDialog.java52
-rw-r--r--src/org/theb/ssh/Pubkey.java133
-rw-r--r--src/org/theb/ssh/SecureShell.java236
-rw-r--r--src/org/theb/ssh/Terminal.java32
-rw-r--r--src/org/theb/ssh/TouchEntropy.java91
-rw-r--r--src/org/theb/ssh/TrileadConnectionThread.java160
32 files changed, 737 insertions, 3236 deletions
diff --git a/src/org/connectbot/AboutActivity.java b/src/org/connectbot/AboutActivity.java
deleted file mode 100644
index a62c0ed..0000000
--- a/src/org/connectbot/AboutActivity.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package org.connectbot;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-import org.connectbot.R;
-
-
-public class AboutActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.act_about);
-
- }
-} \ No newline at end of file
diff --git a/src/org/connectbot/Console.java b/src/org/connectbot/ConsoleActivity.java
index 0561848..9417f65 100644
--- a/src/org/connectbot/Console.java
+++ b/src/org/connectbot/ConsoleActivity.java
@@ -1,11 +1,25 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot;
import org.connectbot.service.TerminalBridge;
-import org.connectbot.service.TerminalBridgeSurface;
import org.connectbot.service.TerminalManager;
-import org.theb.ssh.InteractiveHostKeyVerifier;
-
-import com.trilead.ssh2.Connection;
import de.mud.terminal.vt320;
@@ -14,7 +28,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -27,36 +40,33 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.Window;
import android.view.MenuItem.OnMenuItemClickListener;
-import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
-import android.view.animation.Animation.AnimationListener;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.ViewFlipper;
-import android.widget.LinearLayout.LayoutParams;
-public class Console extends Activity {
+public class ConsoleActivity extends Activity {
+
+ public final static String TAG = ConsoleActivity.class.toString();
- public ViewFlipper flip = null;
- public TerminalManager bound = null;
- public LayoutInflater inflater = null;
+ protected ViewFlipper flip = null;
+ protected TerminalManager bound = null;
+ protected LayoutInflater inflater = null;
private ServiceConnection connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
bound = ((TerminalManager.TerminalBinder) service).getService();
- Log.d(this.getClass().toString(), "ohhai there, i found bridges=" + bound.bridges.size());
+ Log.d(TAG, String.format("Connected to TerminalManager and found bridges.size=%d", bound.bridges.size()));
// clear out any existing bridges and record requested index
flip.removeAllViews();
String requestedNickname = (requested != null) ? requested.getFragment() : null;
int requestedIndex = 0;
-
// first check if we need to create a new session for requested
boolean found = false;
@@ -64,17 +74,17 @@ public class Console extends Activity {
if(bridge.nickname.equals(requestedNickname))
found = true;
}
-
+
+ // if we didnt find the requested connection, try opening it
if(!found) {
try {
- Log.d(this.getClass().toString(), "onServiceConnected() is openConnection() because of unknown requested uri="+requested.toString());
+ Log.d(TAG, String.format("We couldnt find an existing bridge with URI=%s, so creating one now", requested.toString()));
bound.openConnection(requested);
} catch(Exception e) {
- e.printStackTrace();
+ Log.e(TAG, "Problem while trying to create new requested bridge from URI", e);
}
}
-
// create views for all bridges on this service
for(TerminalBridge bridge : bound.bridges) {
@@ -86,7 +96,7 @@ public class Console extends Activity {
overlay.setText(bridge.nickname);
// and add our terminal view control, using index to place behind overlay
- TerminalView terminal = new TerminalView(Console.this, bridge);
+ TerminalView terminal = new TerminalView(ConsoleActivity.this, bridge);
terminal.setId(R.id.console_flip);
view.addView(terminal, 0);
@@ -112,17 +122,21 @@ public class Console extends Activity {
}
};
- public Animation fade_out = null;
- //public String requestedBridge = null;
+ protected Animation fade_out = null;
- public void updateDefault() {
+ /**
+ * Save the currently shown {@link TerminalView} as the default. This is
+ * saved back down into {@link TerminalManager} where we can read it again
+ * later.
+ */
+ protected void updateDefault() {
// update the current default terminal
TerminalView terminal = (TerminalView)flip.getCurrentView().findViewById(R.id.console_flip);
if(bound == null || terminal == null) return;
bound.defaultBridge = terminal.bridge;
}
- public Uri requested;
+ protected Uri requested;
@Override
public void onStart() {
@@ -147,7 +161,7 @@ public class Console extends Activity {
return view.findViewById(id);
}
- public ClipboardManager clipboard;
+ protected ClipboardManager clipboard;
@Override
public void onCreate(Bundle icicle) {
@@ -158,9 +172,6 @@ public class Console extends Activity {
this.clipboard = (ClipboardManager)this.getSystemService(CLIPBOARD_SERVICE);
- // pull out any requested bridge
- //this.requestedBridge = this.getIntent().getExtras().getString(Intent.EXTRA_TEXT);
-
// handle requested console from incoming intent
this.requested = this.getIntent().getData();
@@ -253,7 +264,7 @@ public class Console extends Activity {
flip.setInAnimation(slide_right_in);
flip.setOutAnimation(slide_right_out);
flip.showPrevious();
- Console.this.updateDefault();
+ ConsoleActivity.this.updateDefault();
// show overlay on new slide and start fade
overlay = findCurrentView(R.id.terminal_overlay);
@@ -270,7 +281,7 @@ public class Console extends Activity {
flip.setInAnimation(slide_left_in);
flip.setOutAnimation(slide_left_out);
flip.showNext();
- Console.this.updateDefault();
+ ConsoleActivity.this.updateDefault();
// show overlay on new slide and start fade
overlay = findCurrentView(R.id.terminal_overlay);
@@ -304,13 +315,13 @@ public class Console extends Activity {
}
- public MenuItem copy, paste;
+ protected MenuItem copy, paste;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
- MenuItem add = menu.add(0, 0, Menu.NONE, "Disconnect");
+ MenuItem add = menu.add("Disconnect");
add.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
add.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
@@ -324,12 +335,13 @@ public class Console extends Activity {
}
});
- copy = menu.add(0, 0, Menu.NONE, "Copy");
+ copy = menu.add("Copy");
copy.setIcon(android.R.drawable.ic_menu_set_as);
copy.setEnabled(false);
+ // TODO: implement copy here :)
- paste = menu.add(0, 0, Menu.NONE, "Paste");
+ paste = menu.add("Paste");
paste.setIcon(android.R.drawable.ic_menu_edit);
paste.setEnabled(clipboard.hasText());
paste.setOnMenuItemClickListener(new OnMenuItemClickListener() {
diff --git a/src/org/connectbot/FrontPage.java b/src/org/connectbot/FrontPage.java
deleted file mode 100644
index e854c13..0000000
--- a/src/org/connectbot/FrontPage.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package org.connectbot;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.connectbot.service.TerminalBridge;
-import org.connectbot.service.TerminalManager;
-import org.theb.ssh.InteractiveHostKeyVerifier;
-
-import com.trilead.ssh2.Connection;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnKeyListener;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.SimpleAdapter;
-import android.widget.TextView;
-import android.widget.AdapterView.OnItemClickListener;
-
-
-public class FrontPage extends Activity {
-
- public TerminalManager bound = null;
-
- private ServiceConnection connection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- bound = ((TerminalManager.TerminalBinder) service).getService();
-
- // TODO: update our green bulb icons by checking for existing bridges
- // open up some test sessions
-// try {
-// bound.openConnection("192.168.254.230", 22, "connectbot", "b0tt", "screen", 100);
-// bound.openConnection("192.168.254.230", 22, "connectbot", "b0tt", "screen", 100);
-// bound.openConnection("192.168.254.230", 22, "connectbot", "b0tt", "screen", 100);
-// } catch(Exception e) {
-// e.printStackTrace();
-// }
-
- }
-
- public void onServiceDisconnected(ComponentName className) {
- bound = null;
- }
- };
-
-
- public final static String ITEM_TITLE = "title";
- public final static String ITEM_CAPTION = "caption";
- public final static String ITEM_IMAGE = "image";
-
- public Map<String,?> createItem(String title, String caption, int image) {
- Map<String,String> item = new HashMap<String,String>();
- item.put(ITEM_TITLE, title);
- item.put(ITEM_CAPTION, caption);
- item.put(ITEM_IMAGE, Integer.toString(image));
- return item;
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.act_frontpage);
-
- // start the terminal manager service
- this.startService(new Intent(this, TerminalManager.class));
- this.bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE);
-
-
-
- // create some test hostmasks
- List<Map<String,?>> security = new LinkedList<Map<String,?>>();
- security.add(createItem("user@example.org", "20 minutes ago, connected", android.R.drawable.presence_online));
- security.add(createItem("root@home.example.com", "1 hour ago, connected", android.R.drawable.presence_online));
- security.add(createItem("person@192.168.0.1", "12 days ago", android.R.drawable.presence_invisible));
- security.add(createItem("root@google.com", "never", android.R.drawable.presence_invisible));
- security.add(createItem("nobody@example.net", "14 years ago, broken socket", android.R.drawable.presence_busy));
- security.add(createItem("root@home.example.com", "1 hour ago", android.R.drawable.presence_invisible));
- security.add(createItem("person@192.168.0.1", "12 minutes ago", android.R.drawable.presence_invisible));
-
- final ListView list = (ListView)this.findViewById(R.id.front_hostlist);
- list.setAdapter(new SimpleAdapter(this, security, R.layout.item_host, new String[] { ITEM_TITLE, ITEM_CAPTION, ITEM_IMAGE }, new int[] { R.id.host_title, R.id.host_caption, R.id.host_connected }));
-
- list.setOnItemClickListener(new OnItemClickListener() {
-
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-
- // TODO: actually perform connection process here
- // launch off to console details
- FrontPage.this.startActivity(new Intent(FrontPage.this, Console.class));
-
- }
-
- });
-
-
-// final TextView text = (TextView)this.findViewById(R.id.front_quickconnect);
-// text.setOnKeyListener(new OnKeyListener() {
-//
-// public boolean onKey(View v, int keyCode, KeyEvent event) {
-//
-// // set list filter based on text
-// String filter = text.getText().toString();
-// list.setTextFilterEnabled((filter.length() > 0));
-// list.setFilterText(filter);
-//
-// // TODO Auto-generated method stub
-// return false;
-// }
-//
-// });
-
-
-
-
-
-
-
-
-
- }
-
-}
diff --git a/src/org/connectbot/HostEditor.java b/src/org/connectbot/HostEditorActivity.java
index 97ddc14..522f33a 100644
--- a/src/org/connectbot/HostEditor.java
+++ b/src/org/connectbot/HostEditorActivity.java
@@ -1,3 +1,21 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot;
import java.util.HashMap;
@@ -22,7 +40,7 @@ import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.util.Log;
-public class HostEditor extends PreferenceActivity implements OnSharedPreferenceChangeListener {
+public class HostEditorActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
public class CursorPreferenceHack implements SharedPreferences {
diff --git a/src/org/connectbot/HostList.java b/src/org/connectbot/HostListActivity.java
index 393fdaa..30ec5f9 100644
--- a/src/org/connectbot/HostList.java
+++ b/src/org/connectbot/HostListActivity.java
@@ -1,30 +1,35 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
import java.util.regex.Pattern;
-import org.connectbot.service.TerminalBridge;
import org.connectbot.service.TerminalManager;
-import org.connectbot.util.HostAdapter;
import org.connectbot.util.HostBinder;
import org.connectbot.util.HostDatabase;
-import org.json.JSONObject;
-import org.theb.ssh.InteractiveHostKeyVerifier;
+import org.connectbot.util.UpdateHelper;
-import com.trilead.ssh2.Connection;
import android.app.Activity;
-import android.app.AlertDialog;
+import android.app.ListActivity;
import android.content.ComponentName;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
@@ -53,47 +58,12 @@ import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
-public class HostList extends Activity {
+public class HostListActivity extends ListActivity {
- public final static String UPDATE_URL = "http://connectbot.org/version";
- public final static double VERSION = 1.0;
-
- public Handler versionHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
-
- // handle version update message
- if(!(msg.obj instanceof JSONObject)) return;
- JSONObject json = (JSONObject)msg.obj;
-
- double version = json.optDouble("version");
- String features = json.optString("features");
- final String target = "market://" + json.optString("target");
-
- if(version <= VERSION) return;
-
- new AlertDialog.Builder(HostList.this)
- .setTitle("New version")
- .setMessage(features)
- .setPositiveButton("Yes, upgrade", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(target));
- HostList.this.startActivity(intent);
- }
- })
- .setNegativeButton("Not right now", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- }
- }).create().show();
-
- }
-
- };
-
public Handler updateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
- HostList.this.updateCursor();
+ HostListActivity.this.updateCursor();
}
};
@@ -104,19 +74,18 @@ public class HostList extends Activity {
bound = ((TerminalManager.TerminalBinder) service).getService();
// update our listview binder to find the service
- HostList.this.updateCursor();
+ HostListActivity.this.updateCursor();
}
public void onServiceDisconnected(ComponentName className) {
bound = null;
- HostList.this.updateCursor();
+ HostListActivity.this.updateCursor();
}
};
public HostDatabase hostdb;
public Cursor hosts;
public ListView list;
- public HostAdapter adapter;
public int COL_ID, COL_NICKNAME, COL_USERNAME, COL_HOSTNAME, COL_CONNECTED, COL_PORT;
@@ -177,16 +146,7 @@ public class HostList extends Activity {
}
// start thread to check for new version
- new Thread(new Runnable() {
- public void run() {
- try {
- JSONObject json = new JSONObject(readUrl(UPDATE_URL));
- Message.obtain(versionHandler, -1, json).sendToTarget();
- } catch(Exception e) {
- e.printStackTrace();
- }
- }
- }).start();
+ new UpdateHelper(this);
@@ -195,7 +155,7 @@ public class HostList extends Activity {
// connect with hosts database and populate list
this.hostdb = new HostDatabase(this);
- this.list = (ListView) this.findViewById(R.id.front_hostlist);
+ this.list = this.getListView();
this.updateCursor();
//this.list.setSelector(R.drawable.highlight_disabled_pressed);
@@ -218,6 +178,7 @@ public class HostList extends Activity {
int port = c.getInt(COL_PORT);
String nickname = c.getString(COL_NICKNAME);
+ // create a specific uri that represents this host
Uri uri = Uri.parse(String.format("ssh://%s@%s:%s/#%s", username, hostname, port, nickname));
Intent contents = new Intent(Intent.ACTION_VIEW, uri);
contents.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -225,7 +186,7 @@ public class HostList extends Activity {
if (shortcut) {
// create shortcut if requested
- ShortcutIconResource icon = Intent.ShortcutIconResource.fromContext(HostList.this, R.drawable.icon);
+ ShortcutIconResource icon = Intent.ShortcutIconResource.fromContext(HostListActivity.this, R.drawable.icon);
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, contents);
@@ -236,7 +197,8 @@ public class HostList extends Activity {
finish();
} else {
- HostList.this.startActivity(contents);
+ // otherwise just launch activity to show this host
+ HostListActivity.this.startActivity(contents);
}
@@ -276,9 +238,9 @@ public class HostList extends Activity {
String nickname = String.format("%s@%s", username, hostname);
hostdb.createHost(null, nickname, username, hostname, port, hostdb.COLOR_GRAY);
- Intent intent = new Intent(HostList.this, Console.class);
+ Intent intent = new Intent(HostListActivity.this, ConsoleActivity.class);
intent.setData(Uri.parse(String.format("ssh://%s@%s:%s/#%s", username, hostname, port, nickname)));
- HostList.this.startActivity(intent);
+ HostListActivity.this.startActivity(intent);
}
@@ -287,7 +249,6 @@ public class HostList extends Activity {
// list.setTextFilterEnabled((filter.length() > 0));
// list.setFilterText(filter);
- // TODO Auto-generated method stub
return false;
}
@@ -340,7 +301,7 @@ public class HostList extends Activity {
// }
// });
- sortcolor = menu.add(0, 0, Menu.NONE, "Sort by color");
+ sortcolor = menu.add("Sort by color");
sortcolor.setIcon(android.R.drawable.ic_menu_share);
sortcolor.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
@@ -350,7 +311,7 @@ public class HostList extends Activity {
}
});
- sortlast = menu.add(0, 0, Menu.NONE, "Sort by name");
+ sortlast = menu.add("Sort by name");
sortlast.setIcon(android.R.drawable.ic_menu_share);
sortlast.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
@@ -360,17 +321,17 @@ public class HostList extends Activity {
}
});
- MenuItem keys = menu.add(0, 0, Menu.NONE, "Manage keys");
+ MenuItem keys = menu.add("Manage keys");
keys.setIcon(android.R.drawable.ic_lock_lock);
keys.setEnabled(false);
- MenuItem settings = menu.add(0, 0, Menu.NONE, "Settings");
+ MenuItem settings = menu.add("Settings");
settings.setIcon(android.R.drawable.ic_menu_preferences);
- settings.setIntent(new Intent(HostList.this, SettingsActivity.class));
+ settings.setIntent(new Intent(HostListActivity.this, SettingsActivity.class));
- MenuItem about = menu.add(0, 0, Menu.NONE, "About");
+ MenuItem about = menu.add("About");
about.setIcon(android.R.drawable.ic_menu_help);
- about.setIntent(new Intent(HostList.this, WizardActivity.class));
+ about.setIntent(new Intent(HostListActivity.this, WizardActivity.class));
return true;
@@ -378,36 +339,10 @@ public class HostList extends Activity {
- public String readUrl(String fetchurl) throws Exception {
- byte[] buffer = new byte[1024];
-
- URL url = new URL(fetchurl);
- URLConnection connection = url.openConnection();
- connection.setConnectTimeout(6000);
- connection.setReadTimeout(6000);
- connection.setRequestProperty("User-Agent", String.format("%s %f", this.getResources().getString(R.string.app_name), VERSION));
- connection.connect();
- InputStream is = connection.getInputStream();
- ByteArrayOutputStream os = new ByteArrayOutputStream();
-
- int bytesRead;
- while ((bytesRead = is.read(buffer)) != -1) {
- os.write(buffer, 0, bytesRead);
- }
-
- os.flush();
- os.close();
- is.close();
-
- return new String(os.toByteArray());
- }
-
-
public final static int REQUEST_EDIT = 1;
@Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenu.ContextMenuInfo menuInfo) {
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
// create menu to handle hosts
@@ -430,9 +365,9 @@ public class HostList extends Activity {
MenuItem edit = menu.add("Edit host");
edit.setOnMenuItemClickListener(new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
- Intent intent = new Intent(HostList.this, HostEditor.class);
+ Intent intent = new Intent(HostListActivity.this, HostEditorActivity.class);
intent.putExtra(Intent.EXTRA_TITLE, id);
- HostList.this.startActivityForResult(intent, REQUEST_EDIT);
+ HostListActivity.this.startActivityForResult(intent, REQUEST_EDIT);
return false;
}
});
diff --git a/src/org/connectbot/R.java b/src/org/connectbot/R.java
index bc34353..416addd 100644
--- a/src/org/connectbot/R.java
+++ b/src/org/connectbot/R.java
@@ -38,61 +38,22 @@ public final class R {
public static final int odd_stripe=0x7f020007;
}
public static final class id {
- public static final int action_next=0x7f09000e;
- public static final int action_prev=0x7f09000d;
- public static final int add=0x7f090015;
- public static final int cancel=0x7f090016;
- public static final int console_flip=0x7f090002;
- public static final int copyright=0x7f090001;
- public static final int dismiss=0x7f09001d;
- public static final int edit_emulation=0x7f090009;
- public static final int edit_hostname=0x7f090007;
- public static final int edit_nickname=0x7f090005;
- public static final int edit_port=0x7f090008;
- public static final int edit_scrollback=0x7f09000a;
- public static final int edit_username=0x7f090006;
- public static final int front_hostlist=0x7f090003;
- public static final int front_quickconnect=0x7f090004;
- public static final int generate=0x7f090021;
- public static final int host_caption=0x7f090019;
- public static final int host_connected=0x7f090017;
- public static final int host_title=0x7f090018;
- public static final int hostname=0x7f090012;
- public static final int hostnameLabel=0x7f090011;
- public static final int icon=0x7f090000;
- public static final int keyName=0x7f090022;
- public static final int message=0x7f09001c;
- public static final int ok=0x7f090020;
- public static final int password=0x7f09001f;
- public static final int passwordLabel=0x7f09001e;
- public static final int port=0x7f090014;
- public static final int portLabel=0x7f090013;
- public static final int shell=0x7f09001b;
- public static final int terminal=0x7f090023;
- public static final int terminal_overlay=0x7f09001a;
- public static final int username=0x7f090010;
- public static final int usernameLabel=0x7f09000f;
- public static final int wizard_flipper=0x7f09000c;
- public static final int wizard_scroll=0x7f09000b;
+ public static final int action_next=0x7f090005;
+ public static final int action_prev=0x7f090004;
+ public static final int console_flip=0x7f090000;
+ public static final int front_quickconnect=0x7f090001;
+ public static final int terminal_overlay=0x7f090006;
+ public static final int wizard_flipper=0x7f090003;
+ public static final int wizard_scroll=0x7f090002;
}
public static final class layout {
- public static final int about_dialog=0x7f030000;
- public static final int act_about=0x7f030001;
- public static final int act_console=0x7f030002;
- public static final int act_frontpage=0x7f030003;
- public static final int act_hosteditor=0x7f030004;
- public static final int act_hostlist=0x7f030005;
- public static final int act_wizard=0x7f030006;
- public static final int host_editor=0x7f030007;
- public static final int item_host=0x7f030008;
- public static final int item_terminal=0x7f030009;
- public static final int main=0x7f03000a;
- public static final int message_dialog=0x7f03000b;
- public static final int password_dialog=0x7f03000c;
- public static final int pubkey=0x7f03000d;
- public static final int secure_shell=0x7f03000e;
- public static final int wiz_eula=0x7f03000f;
- public static final int wiz_features=0x7f030010;
+ 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 class string {
public static final int alert_disconnect_msg=0x7f070015;
diff --git a/src/org/connectbot/SettingsActivity.java b/src/org/connectbot/SettingsActivity.java
index 2036958..2b76c68 100644
--- a/src/org/connectbot/SettingsActivity.java
+++ b/src/org/connectbot/SettingsActivity.java
@@ -1,3 +1,21 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot;
import android.os.Bundle;
@@ -9,7 +27,7 @@ public class SettingsActivity extends PreferenceActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
-
+
}
}
diff --git a/src/org/connectbot/TerminalView.java b/src/org/connectbot/TerminalView.java
index 0e7e283..8e4c893 100644
--- a/src/org/connectbot/TerminalView.java
+++ b/src/org/connectbot/TerminalView.java
@@ -1,21 +1,45 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot;
import org.connectbot.service.TerminalBridge;
-import org.connectbot.service.TerminalBridgeSurface;
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Paint;
-import android.view.SurfaceHolder;
+import android.graphics.PixelXorXfermode;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
+/**
+ * User interface {@link View} for showing a TerminalBridge in an
+ * {@link Activity}. Handles drawing bitmap updates and passing keystrokes down
+ * to terminal.
+ *
+ * @author jsharkey
+ */
public class TerminalView extends View {
- public final Context context;
- public final TerminalBridge bridge;
- public final Paint paint;
+ protected final Context context;
+ protected final TerminalBridge bridge;
+ protected final Paint paint;
+ protected final Paint cursorPaint;
public TerminalView(Context context, TerminalBridge bridge) {
super(context);
@@ -28,6 +52,10 @@ public class TerminalView extends View {
this.setFocusable(true);
this.setFocusableInTouchMode(true);
+ this.cursorPaint = new Paint();
+ this.cursorPaint.setColor(bridge.color[bridge.COLOR_FG_STD]);
+ this.cursorPaint.setXfermode(new PixelXorXfermode(bridge.color[bridge.COLOR_BG_STD]));
+
// connect our view up to the bridge
this.setOnKeyListener(bridge);
@@ -46,9 +74,23 @@ public class TerminalView extends View {
@Override
public void onDraw(Canvas canvas) {
- // draw the bridge if it exists
if(this.bridge.bitmap != null) {
+
+ // draw the bridge bitmap if it exists
canvas.drawBitmap(this.bridge.bitmap, 0, 0, this.paint);
+
+ // also draw cursor if visible
+ if(this.bridge.buffer.isCursorVisible()) {
+ int x = this.bridge.buffer.getCursorColumn() * this.bridge.charWidth;
+ int y = (this.bridge.buffer.getCursorRow()
+ + this.bridge.buffer.screenBase - this.bridge.buffer.windowBase)
+ * this.bridge.charHeight;
+
+ canvas.drawRect(x, y, x + this.bridge.charWidth,
+ y + this.bridge.charHeight, cursorPaint);
+
+ }
+
}
}
diff --git a/src/org/connectbot/TerminalViewSurface.java b/src/org/connectbot/TerminalViewSurface.java
deleted file mode 100644
index cb68696..0000000
--- a/src/org/connectbot/TerminalViewSurface.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.connectbot;
-
-import org.connectbot.service.TerminalBridgeSurface;
-
-import android.content.Context;
-import android.view.KeyEvent;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.ViewGroup.LayoutParams;
-
-public class TerminalViewSurface extends SurfaceView {
-
- public final Context context;
- public final TerminalBridgeSurface bridge;
-
- public TerminalViewSurface(Context context, TerminalBridgeSurface bridge) {
- super(context);
-
- this.context = context;
- this.bridge = bridge;
-
- this.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
- this.setFocusable(true);
- this.setFocusableInTouchMode(true);
-
-
- // connect our surface up to the bridge
- this.getHolder().setType(SurfaceHolder.SURFACE_TYPE_HARDWARE);
- this.getHolder().addCallback(bridge);
- this.setOnKeyListener(bridge);
-
- }
-
- // TODO: make sure we pass any keystrokes down to bridge
-
-
-}
diff --git a/src/org/connectbot/WizardActivity.java b/src/org/connectbot/WizardActivity.java
index 0fce80f..1d4c10f 100644
--- a/src/org/connectbot/WizardActivity.java
+++ b/src/org/connectbot/WizardActivity.java
@@ -1,3 +1,21 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot;
import android.app.Activity;
@@ -64,12 +82,6 @@ public class WizardActivity extends Activity {
protected ViewFlipper flipper = null;
protected Button next, prev;
- protected ImageView finger = null,
- cross = null;
-
- protected Animation animFinger = null,
- animCross = null;
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/src/org/connectbot/service/TerminalBridge.java b/src/org/connectbot/service/TerminalBridge.java
index 733300c..2a6f276 100644
--- a/src/org/connectbot/service/TerminalBridge.java
+++ b/src/org/connectbot/service/TerminalBridge.java
@@ -1,46 +1,63 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot.service;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import org.theb.ssh.InteractiveHostKeyVerifier;
-import org.theb.ssh.JTATerminalView;
-
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
-import android.graphics.Rect;
+import android.graphics.PixelXorXfermode;
import android.graphics.Typeface;
import android.graphics.Bitmap.Config;
import android.graphics.Paint.FontMetricsInt;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
-import android.view.SurfaceHolder;
import android.view.View;
import android.view.View.OnKeyListener;
-import com.trilead.ssh2.InteractiveCallback;
import com.trilead.ssh2.KnownHosts;
import com.trilead.ssh2.ServerHostKeyVerifier;
import com.trilead.ssh2.Session;
import com.trilead.ssh2.Connection;
-import com.trilead.ssh2.signature.RSAPublicKey;
import de.mud.terminal.VDUBuffer;
import de.mud.terminal.VDUDisplay;
import de.mud.terminal.vt320;
-// provides a bridge between the mud buffer and a surfaceholder
+/**
+ * Provides a bridge between a MUD terminal buffer and a possible TerminalView.
+ * This separation allows us to keep the TerminalBridge running in a background
+ * service. A TerminalView shares down a bitmap that we can use for rendering
+ * when available.
+ *
+ * This class also provides SSH hostkey verification prompting, and password
+ * prompting.
+ */
public class TerminalBridge implements VDUDisplay, OnKeyListener {
- public final Connection connection;
- public final String nickname, username;
- public final Paint defaultPaint;
- public Session session;
+ public final static String TAG = TerminalBridge.class.toString();
public final static int TERM_WIDTH_CHARS = 80,
TERM_HEIGHT_CHARS = 24,
@@ -50,37 +67,50 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
public static final String AUTH_PUBLICKEY = "publickey",
AUTH_PASSWORD = "password";
- public OutputStream stdin;
- public InputStream stdout;
+ private int darken(int color) {
+ return Color.argb(0xFF,
+ (int)(Color.red(color) * 0.8),
+ (int)(Color.green(color) * 0.8),
+ (int)(Color.blue(color) * 0.8)
+ );
+ }
+
+ public int color[] = { Color.BLACK, Color.RED, Color.GREEN, Color.YELLOW,
+ Color.BLUE, Color.MAGENTA, Color.CYAN, Color.WHITE, };
+
+ public int darkerColor[] = new int[color.length];
+
+ public final static int COLOR_FG_STD = 7;
+ public final static int COLOR_BG_STD = 0;
+
+ public final String nickname;
+ protected final String username;
+
+ protected final Connection connection;
+ protected Session session;
+
+ protected final Paint defaultPaint;
+
+ protected OutputStream stdin;
+ protected InputStream stdout;
- public Thread relay;
+ protected Thread relay;
- public View parent = null;
public Bitmap bitmap = null;
- public Canvas canvas = new Canvas();
public VDUBuffer buffer = null;
+ protected View parent = null;
+ protected Canvas canvas = new Canvas();
+
private boolean ctrlPressed = false;
public class HostKeyVerifier implements ServerHostKeyVerifier {
- // hex routine adapted from
- // http://forums.sun.com/thread.jspa?threadID=252591&messageID=2272668
-
- private final char[] hex = "0123456789abcdef".toCharArray();
-
- public String hexdump(byte[] buf) {
- StringBuffer out = new StringBuffer();
- for(int i = 0; i < buf.length; i++) {
- int value = buf[i] + 127;
- out.append(":" + hex[(value>>>4)&0xf] + hex[value&0xf]);
- }
- return out.toString().substring(1);
- }
-
public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) throws Exception {
+
// TODO: check against known key, prompt user if unknown or missing key
+ // TODO: check to see what hostkey checking the trilead library offers
KnownHosts hosts = new KnownHosts();
switch(hosts.verifyHostkey(hostname, serverHostKeyAlgorithm, serverHostKey)) {
@@ -106,8 +136,12 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
}
+ /**
+ * Create new terminal bridge with following parameters. We will immediately
+ * launch thread to start SSH connection and handle any hostkey verification
+ * and password authentication.
+ */
public TerminalBridge(final String nickname, final String username, final String hostname, final int port) throws Exception {
- // newer version of TerminalBridge that will dump all connection progress to the display
this.nickname = nickname;
this.username = username;
@@ -116,8 +150,10 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
this.defaultPaint = new Paint();
this.defaultPaint.setAntiAlias(true);
this.defaultPaint.setTypeface(Typeface.MONOSPACE);
+
this.setFontSize(DEFAULT_FONT_SIZE);
+ // prepare our "darker" colors
for(int i = 0; i < color.length; i++)
this.darkerColor[i] = darken(color[i]);
@@ -128,7 +164,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
try {
TerminalBridge.this.stdin.write(b);
} catch (IOException e) {
- e.printStackTrace();
+ Log.e(TAG, "Problem handling incoming data in vt320() thread", e);
}
}
@@ -139,7 +175,6 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
}
};
- this.scrollback = scrollback;
this.buffer.setScreenSize(TERM_WIDTH_CHARS, TERM_HEIGHT_CHARS, true);
this.buffer.setBufferSize(scrollback);
this.buffer.setDisplay(this);
@@ -160,7 +195,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
promptPassword();
}
} catch (IOException e) {
- e.printStackTrace();
+ Log.e(TAG, "Problem in SSH connection thread", e);
}
}
@@ -168,38 +203,50 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
}
- public void outputLine(String line) {
+ /**
+ * Convenience method for writing a line into the underlying MUD buffer.
+ */
+ protected void outputLine(String line) {
this.buffer.putString(0, this.buffer.getCursorRow(), line);
this.buffer.setCursorPosition(0, this.buffer.getCursorRow() + 1);
this.redraw();
}
- public void promptPassword() {
+ protected void promptPassword() {
this.outputLine("Password: ");
}
+ /**
+ * Attempt to try password authentication using given string.
+ */
public void tryPassword(String password) {
try {
// try authenticating with given password
- Log.d(this.getClass().toString(), String.format("tryPassword(password=%s) and username=%s", password, username));
+ Log.d(TAG, "Attempting to try password authentication");
if(this.connection.authenticateWithPassword(this.username, password)) {
this.buffer.deleteArea(0, 0, this.buffer.getColumns(), this.buffer.getRows());
finishConnection();
return;
}
} catch (IOException e) {
- e.printStackTrace();
+ Log.e(TAG, "Problem while trying to authenticate with password", e);
}
this.outputLine("Permission denied, please try again.");
this.promptPassword();
}
-
- public void finishConnection() {
+ /**
+ * Internal method to request actual PTY terminal once we've finished
+ * authentication. If called before authenticated, it will just fail.
+ */
+ protected void finishConnection() {
try {
this.session = connection.openSession();
- this.session.requestPTY("screen", 0, 0, 0, 0, null); // previously tried vt100, xterm, but "screen" works the best
+
+ // previously tried vt100 and xterm for emulation modes
+ // "screen" works the best for color and escape codes
+ this.session.requestPTY("screen", 0, 0, 0, 0, null);
this.session.startShell();
// grab stdin/out from newly formed session
@@ -220,7 +267,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
TerminalBridge.this.redraw();
}
} catch (IOException e) {
- e.printStackTrace();
+ Log.e(TAG, "Problem while handling incoming data in relay thread", e);
break;
}
}
@@ -232,14 +279,17 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
this.setFontSize(this.fontSize);
} catch (IOException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
+ Log.e(TAG, "Problem while trying to create PTY in finishConnection()", e1);
}
}
+ /**
+ * Force disconnection of this terminal bridge.
+ */
public void dispose() {
- // meh this is buggy if the host isnt alive, so just spawn to thread for now
+ // disconnection request hangs if we havent really connected to a host yet
+ // temporary fix is to just spawn disconnection into a thread
new Thread(new Runnable() {
public void run() {
if(session != null)
@@ -250,17 +300,27 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
}
public KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
-
- StringBuffer collected = new StringBuffer();
+ /**
+ * 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
+ * or passwords, but otherwise we pass them directly over to the SSH host.
+ */
public boolean onKey(View v, int keyCode, KeyEvent event) {
// pass through any keystrokes to output stream
- //Log.d(this.getClass().toString(), "onKey() code="+keyCode);
+ // ignore any key-up events
if(event.getAction() == KeyEvent.ACTION_UP) return false;
+
try {
-
- // check for resizing keys
+ // check for terminal resizing keys
+ // TODO: see if there is a way to make sure we dont "blip"
if(keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
this.setFontSize(this.fontSize + 2);
return true;
@@ -324,7 +384,7 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
}
} catch (IOException e) {
- e.printStackTrace();
+ Log.e(TAG, "Problem while trying to handle an onKey() event", e);
}
return false;
}
@@ -334,11 +394,16 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
charHeight = -1,
charDescent = -1;
- public float fontSize = -1;
+ protected float fontSize = -1;
- public int scrollback = 120;
+ // TODO: read this scrollback value from preferences framework?
+ protected int scrollback = 120;
- public void setFontSize(float size) {
+ /**
+ * Request a different font size. Will make call to parentChanged() to make
+ * sure we resize PTY if needed.
+ */
+ protected void setFontSize(float size) {
this.defaultPaint.setTextSize(size);
this.fontSize = size;
@@ -356,8 +421,17 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
this.parentChanged(this.parent);
}
- public boolean fullRedraw = false;
+ /**
+ * Flag indicating if we should perform a full-screen redraw during our next
+ * rendering pass.
+ */
+ protected boolean fullRedraw = false;
+ /**
+ * Something changed in our parent {@link TerminalView}, maybe it's a new
+ * parent, or maybe it's an updated font size. We should recalculate
+ * terminal size information and request a PTY resize.
+ */
public synchronized void parentChanged(View parent) {
this.parent = parent;
@@ -382,22 +456,29 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
int termHeight = height / charHeight;
try {
+ // request a terminal pty resize
buffer.setScreenSize(termWidth, termHeight, true);
if(session != null)
session.resizePTY(termWidth, termHeight);
} catch(Exception e) {
- e.printStackTrace();
+ Log.e(TAG, "Problem while trying to resize screen or PTY", e);
}
// force full redraw with new buffer size
this.fullRedraw = true;
this.redraw();
- Log.d(this.getClass().toString(), "parentChanged() now width=" + termWidth + ", height=" + termHeight);
+ Log.i(TAG, String.format("parentChanged() now width=%d, height=%d", termWidth, termHeight));
}
+ /**
+ * Somehow our parent {@link TerminalView} was destroyed. Now we don't need
+ * to redraw anywhere, and we can recycle our internal bitmap.
+ */
public synchronized void parentDestroyed() {
this.parent = null;
+ if(this.bitmap != null)
+ this.bitmap.recycle();
this.bitmap = null;
this.canvas.setBitmap(null);
}
@@ -410,22 +491,6 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
return buffer;
}
- private int darken(int color) {
- return Color.argb(0xFF,
- (int)(Color.red(color) * 0.8),
- (int)(Color.green(color) * 0.8),
- (int)(Color.blue(color) * 0.8)
- );
- }
-
- private int color[] = { Color.BLACK, Color.RED, Color.GREEN, Color.YELLOW,
- Color.BLUE, Color.MAGENTA, Color.CYAN, Color.WHITE, };
-
- private int darkerColor[] = new int[color.length];
-
- private final static int COLOR_FG_STD = 7;
- private final static int COLOR_BG_STD = 0;
-
public long lastDraw = 0;
public long drawTolerance = 100;
@@ -433,22 +498,14 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
// render our buffer only if we have a surface
if(this.parent == null) return;
- long time = System.currentTimeMillis();
int lines = 0;
- // only worry about rendering if its been awhile
- //if(time - lastDraw < drawTolerance) return;
- //lastDraw = time;
-
int fg, bg;
boolean entireDirty = buffer.update[0] || this.fullRedraw;
// walk through all lines in the buffer
for(int l = 0; l < buffer.height; l++) {
-// if(entireDirty)
-// Log.w("BUFFERDUMP", new String(buffer.charArray[l]));
-
// check if this line is dirty and needs to be repainted
// also check for entire-buffer dirty flags
if(!entireDirty && !buffer.update[l + 1]) continue;
@@ -457,9 +514,6 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
// reset dirty flag for this line
buffer.update[l + 1] = false;
- // lock this entire row as being dirty
- //Rect dirty = new Rect(0, l * charHeight, buffer.width * charWidth, (l + 1) * charHeight);
-
// walk through all characters in this line
for (int c = 0; c < buffer.width; c++) {
int addr = 0;
@@ -511,26 +565,17 @@ public class TerminalBridge implements VDUDisplay, OnKeyListener {
// advance to the next text block with different characteristics
c += addr - 1;
}
-
- // unlock this row and update
- //this.current.unlockCanvasAndPost(canvas);
}
// reset entire-buffer flags
buffer.update[0] = false;
this.fullRedraw = false;
- // dump out rendering statistics
- time = System.currentTimeMillis() - time;
- //Log.d(this.getClass().toString(), "redraw called and updated lines=" + lines + " taking ms=" + time);
-
this.parent.postInvalidate();
}
public void updateScrollBar() {
- // TODO Auto-generated method stub
-
}
diff --git a/src/org/connectbot/service/TerminalBridgeSurface.java b/src/org/connectbot/service/TerminalBridgeSurface.java
deleted file mode 100644
index 3fa0c83..0000000
--- a/src/org/connectbot/service/TerminalBridgeSurface.java
+++ /dev/null
@@ -1,310 +0,0 @@
-package org.connectbot.service;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.theb.ssh.JTATerminalView;
-
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.Paint.FontMetricsInt;
-import android.util.Log;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.SurfaceHolder;
-import android.view.View;
-import android.view.View.OnKeyListener;
-
-import com.trilead.ssh2.Session;
-import com.trilead.ssh2.Connection;
-
-import de.mud.terminal.VDUBuffer;
-import de.mud.terminal.VDUDisplay;
-import de.mud.terminal.vt320;
-
-
-// provides a bridge between the mud buffer and a surfaceholder
-public class TerminalBridgeSurface implements SurfaceHolder.Callback, VDUDisplay, OnKeyListener {
-
- public final Connection connection;
- public final Session session;
-
- public final static int TERM_WIDTH_CHARS = 80,
- TERM_HEIGHT_CHARS = 24,
- DEFAULT_FONT_SIZE = 10;
-
- public final static String ENCODING = "ASCII";
-
- public final OutputStream stdin;
- public final InputStream stdout;
-
- public final Paint defaultPaint;
-
- public final Thread relay;
-
- public SurfaceHolder current = null;
- public VDUBuffer buffer = null;
-
- public TerminalBridgeSurface(Connection connection) throws Exception {
- // create a terminal bridge from an SSH connection over to a SurfaceHolder
- // will open a new session and handle rendering to the Surface if present
-
- try {
- this.connection = connection;
- this.session = connection.openSession();
- this.session.requestPTY("xterm", TERM_WIDTH_CHARS, TERM_HEIGHT_CHARS, 0, 0, null);
- this.session.startShell();
-
- // grab stdin/out from newly formed session
- this.stdin = this.session.getStdin();
- this.stdout = this.session.getStdout();
-
- // create our default paint
- this.defaultPaint = new Paint();
- this.defaultPaint.setAntiAlias(true);
- this.defaultPaint.setTypeface(Typeface.MONOSPACE);
- this.setFontSize(DEFAULT_FONT_SIZE);
-
- // create terminal buffer and handle outgoing data
- // this is probably status reply information
- this.buffer = new vt320() {
- public void write(byte[] b) {
- try {
- Log.d("STDIN", new String(b));
- TerminalBridgeSurface.this.stdin.write(b);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- public void sendTelnetCommand(byte cmd) {
- }
-
- public void setWindowSize(int c, int r) {
- }
- };
- this.buffer.setDisplay(this);
-
- // create thread to relay incoming connection data to buffer
- this.relay = new Thread(new Runnable() {
- public void run() {
- byte[] b = new byte[256];
- int n = 0;
- while(n >= 0) {
- try {
- n = TerminalBridgeSurface.this.stdout.read(b);
- if(n > 0) {
- // pass along data to buffer, then redraw any results
- ((vt320)TerminalBridgeSurface.this.buffer).putString(new String(b, 0, n, ENCODING));
- TerminalBridgeSurface.this.redraw();
- }
- } catch (IOException e) {
- e.printStackTrace();
- break;
- }
- }
- }
- });
- this.relay.start();
-
- } catch(Exception e) {
- throw e;
- }
-
- }
-
- KeyCharacterMap keymap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
-
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // pass through any keystrokes to output stream
- if(event.getAction() == KeyEvent.ACTION_UP) return false;
- try {
- int key = keymap.get(keyCode, event.getMetaState());
- switch(keyCode) {
- case KeyEvent.KEYCODE_DEL: stdin.write(0x08); break;
- case KeyEvent.KEYCODE_ENTER: ((vt320)buffer).keyTyped(vt320.KEY_ENTER, ' ', event.getMetaState()); break;
- case KeyEvent.KEYCODE_DPAD_LEFT: ((vt320)buffer).keyPressed(vt320.KEY_LEFT, ' ', event.getMetaState()); break;
- case KeyEvent.KEYCODE_DPAD_UP: ((vt320)buffer).keyPressed(vt320.KEY_UP, ' ', event.getMetaState()); break;
- case KeyEvent.KEYCODE_DPAD_DOWN: ((vt320)buffer).keyPressed(vt320.KEY_DOWN, ' ', event.getMetaState()); break;
- case KeyEvent.KEYCODE_DPAD_RIGHT: ((vt320)buffer).keyPressed(vt320.KEY_RIGHT, ' ', event.getMetaState()); break;
- default: this.stdin.write(key);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return true;
- }
-
- public int charWidth = -1,
- charHeight = -1,
- charDescent = -1;
-
- public void setFontSize(float size) {
- this.defaultPaint.setTextSize(size);
-
- // read new metrics to get exact pixel dimensions
- FontMetricsInt fm = this.defaultPaint.getFontMetricsInt();
- this.charDescent = fm.descent;
-
- float[] widths = new float[1];
- this.defaultPaint.getTextWidths("X", widths);
- this.charWidth = (int)widths[0];
- this.charHeight = Math.abs(fm.top) + Math.abs(fm.descent);
-
- // we probably need to resize the viewport with changed size
- // behave just as if the surface changed to reset buffer size
- this.surfaceChanged(this.current, -1, -1, -1);
- }
-
- public boolean newSurface = false;
-
- public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-
- // mark that we need the entire surface repainted
- this.current = holder;
- this.newSurface = true;
-
- if(this.current == null) return;
-
- // resize the underlying buffer as needed
- Rect size = this.current.getSurfaceFrame();
- int termWidth = size.width() / charWidth;
- int termHeight = size.height() / charHeight;
-
- buffer.setScreenSize(termWidth, termHeight, true);
- buffer.height = termHeight; // TODO: is this really needed?
-
- Log.d(this.getClass().toString(), "surfaceChanged() now width=" + termWidth + ", height=" + termHeight);
- this.redraw();
-
- }
-
- public synchronized void surfaceCreated(SurfaceHolder holder) {
- // someone created our Surface, so resize terminal as needed and repaint
- // we handle this just like we would a changing surface
- this.surfaceChanged(holder, -1, -1, -1);
-
- }
-
- public synchronized void surfaceDestroyed(SurfaceHolder holder) {
- this.current = null;
- this.newSurface = false;
-
- }
-
-
- public void setVDUBuffer(VDUBuffer buffer) {
- this.buffer = buffer;
- }
-
- public VDUBuffer getVDUBuffer() {
- return buffer;
- }
-
- private int color[] = { Color.BLACK, Color.RED, Color.GREEN, Color.YELLOW,
- Color.BLUE, Color.MAGENTA, Color.CYAN, Color.WHITE, };
-
- private int darkerColor[] = color;
-
- private final static int COLOR_FG_STD = 7;
- private final static int COLOR_BG_STD = 0;
-
- public void redraw() {
- // render our buffer only if we have a surface
- if(this.current == null) return;
-
- long time = System.currentTimeMillis();
- int lines = 0;
-
- int fg, bg;
- boolean entireDirty = buffer.update[0] || newSurface;
-
- // walk through all lines in the buffer
- for(int l = 0; l < buffer.height; l++) {
-
- // check if this line is dirty and needs to be repainted
- // also check for entire-buffer dirty flags
- if(!entireDirty && !buffer.update[l + 1]) continue;
- lines++;
-
- // reset dirty flag for this line
- buffer.update[l + 1] = false;
-
- // lock this entire row as being dirty
- Rect dirty = new Rect(0, l * charHeight, buffer.width * charWidth, (l + 1) * charHeight);
- Canvas canvas = this.current.lockCanvas(dirty);
-
- // walk through all characters in this line
- for (int c = 0; c < buffer.width; c++) {
- int addr = 0;
- int currAttr = buffer.charAttributes[buffer.windowBase + l][c];
-
- // reset default colors
- fg = color[COLOR_FG_STD];
- bg = color[COLOR_BG_STD];
-
- // check if foreground color attribute is set
- if((currAttr & VDUBuffer.COLOR_FG) != 0)
- fg = color[((currAttr & VDUBuffer.COLOR_FG) >> VDUBuffer.COLOR_FG_SHIFT) - 1];
-
- // check if background color attribute is set
- if((currAttr & VDUBuffer.COLOR_BG) != 0)
- bg = darkerColor[((currAttr & VDUBuffer.COLOR_BG) >> VDUBuffer.COLOR_BG_SHIFT) - 1];
-
- // support character inversion by swapping background and foreground color
- if ((currAttr & VDUBuffer.INVERT) != 0) {
- int swapc = bg;
- bg = fg;
- fg = swapc;
- }
-
- // correctly set bold and underlined attributes if requested
- this.defaultPaint.setFakeBoldText((currAttr & VDUBuffer.BOLD) != 0);
- this.defaultPaint.setUnderlineText((currAttr & VDUBuffer.UNDERLINE) != 0);
-
- // determine the amount of continuous characters with the same settings and print them all at once
- while(c + addr < buffer.width && buffer.charAttributes[buffer.windowBase + l][c + addr] == currAttr) {
- addr++;
- }
-
- // clear this dirty area with background color
- this.defaultPaint.setColor(bg);
- canvas.drawRect(c * charWidth, l * charHeight, (c + addr) * charWidth, (l + 1) * charHeight, this.defaultPaint);
-
- // write the text string starting at 'c' for 'addr' number of characters
- this.defaultPaint.setColor(fg);
- if((currAttr & VDUBuffer.INVISIBLE) == 0)
- canvas.drawText(buffer.charArray[buffer.windowBase + l], c,
- addr, c * charWidth, ((l + 1) * charHeight) - charDescent,
- this.defaultPaint);
-
- // advance to the next text block with different characteristics
- c += addr - 1;
- }
-
- // unlock this row and update
- this.current.unlockCanvasAndPost(canvas);
- }
-
- // reset entire-buffer flags
- buffer.update[0] = false;
- this.newSurface = false;
-
- // dump out rendering statistics
- time = System.currentTimeMillis() - time;
- Log.d(this.getClass().toString(), "redraw called and updated lines=" + lines + " taking ms=" + time);
-
- }
-
- public void updateScrollBar() {
- // TODO Auto-generated method stub
-
- }
-
-
-
-}
diff --git a/src/org/connectbot/service/TerminalManager.java b/src/org/connectbot/service/TerminalManager.java
index 02a9d5f..5968299 100644
--- a/src/org/connectbot/service/TerminalManager.java
+++ b/src/org/connectbot/service/TerminalManager.java
@@ -1,10 +1,27 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot.service;
import java.util.LinkedList;
import java.util.List;
import org.connectbot.util.HostDatabase;
-import org.theb.ssh.InteractiveHostKeyVerifier;
import com.trilead.ssh2.Connection;
@@ -15,76 +32,78 @@ import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
+/**
+ * Manager for SSH connections that runs as a background service. This service
+ * holds a list of currently connected SSH bridges that are ready for connection
+ * up to a GUI if needed.
+ *
+ * @author jsharkey
+ */
public class TerminalManager extends Service {
+ public final static String TAG = TerminalManager.class.toString();
+
public List<TerminalBridge> bridges = new LinkedList<TerminalBridge>();
public TerminalBridge defaultBridge = null;
-
+
@Override
public void onCreate() {
- Log.w(this.getClass().toString(), "onCreate()");
+ Log.i(TAG, "Starting background service");
}
@Override
public void onDestroy() {
- Log.w(this.getClass().toString(), "onDestroy()");
- // disconnect and dispose of any bridges
+ Log.i(TAG, "Destroying background service");
+
+ // disconnect and dispose of any existing bridges
for(TerminalBridge bridge : bridges)
bridge.dispose();
+
}
-
-// public void openConnection(Connection conn, String nickname, String emulation, int scrollback) throws Exception {
-// try {
-// TerminalBridge bridge = new TerminalBridge(conn, nickname, emulation, scrollback);
-// this.bridges.add(bridge);
-// } catch (Exception e) {
-// throw e;
-// }
-// }
-//
-// public void openConnection(String nickname, String host, int port, String user, String pass, String emulation, int scrollback) throws Exception {
-// try {
-// Connection conn = new Connection(host, port);
-// conn.connect(new InteractiveHostKeyVerifier());
-// if(conn.isAuthMethodAvailable(user, "password")) {
-// conn.authenticateWithPassword(user, pass);
-// }
-// TerminalBridge bridge = new TerminalBridge(conn, nickname, emulation, scrollback);
-// this.bridges.add(bridge);
-// } catch (Exception e) {
-// throw e;
-// }
-// }
-
+
+ /**
+ * Open a new SSH session using the given parameters.
+ */
public void openConnection(String nickname, String hostname, String username, int port) throws Exception {
+ // throw exception if terminal already open
+ if(this.findBridge(nickname) != null) {
+ throw new Exception("Connection already open for that nickname");
+ }
+
TerminalBridge bridge = new TerminalBridge(nickname, username, hostname, port);
this.bridges.add(bridge);
- // also update database with new time
+ // also update database with new connected time
this.touchHost(nickname);
}
+ /**
+ * Open a new SSH session by reading parameters from the given URI. Follows
+ * format <code>ssh://user@host:port/#nickname</code>
+ */
public void openConnection(Uri uri) throws Exception {
String nickname = uri.getFragment();
String username = uri.getUserInfo();
String hostname = uri.getHost();
int port = uri.getPort();
- TerminalBridge bridge = new TerminalBridge(nickname, username, hostname, port);
- this.bridges.add(bridge);
-
- // also update database with new time
- this.touchHost(nickname);
+ this.openConnection(nickname, hostname, username, port);
}
+ /**
+ * Update the last-connected value for the given nickname by passing through
+ * to {@link HostDatabase}.
+ */
protected void touchHost(String nickname) {
- // also update database with new time
HostDatabase hostdb = new HostDatabase(this);
hostdb.touchHost(nickname);
hostdb.close();
}
-
+
+ /**
+ * Find the {@link TerminalBridge} with the given nickname.
+ */
public TerminalBridge findBridge(String nickname) {
// find the first active bridge with given nickname
for(TerminalBridge bridge : bridges) {
@@ -93,7 +112,11 @@ public class TerminalManager extends Service {
}
return null;
}
-
+
+ /**
+ * Force disconnection of this {@link TerminalBridge} and remove it from our
+ * internal list of active connections.
+ */
public void disconnect(TerminalBridge bridge) {
bridge.dispose();
this.bridges.remove(bridge);
@@ -111,7 +134,7 @@ public class TerminalManager extends Service {
@Override
public IBinder onBind(Intent intent) {
- Log.w(this.getClass().toString(), "onBind()");
+ Log.i(TAG, "Someone bound to TerminalManager");
return binder;
}
diff --git a/src/org/connectbot/util/HostBinder.java b/src/org/connectbot/util/HostBinder.java
index a995931..7c78c26 100644
--- a/src/org/connectbot/util/HostBinder.java
+++ b/src/org/connectbot/util/HostBinder.java
@@ -1,3 +1,21 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot.util;
import org.connectbot.R;
@@ -14,6 +32,14 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.SimpleCursorAdapter.ViewBinder;
+/**
+ * Binder used to help interpret a HostDatabase cursor into a ListView for
+ * display. Specifically, it controls the green "bulb" icon by checking against
+ * TerminalManager for status, and shows the last-connected time in a
+ * user-friendly format like "6 days ago."
+ *
+ * @author jsharkey
+ */
public class HostBinder implements ViewBinder {
protected final TerminalManager manager;
@@ -25,17 +51,15 @@ public class HostBinder implements ViewBinder {
this.red = res.getColorStateList(R.color.red);
this.green = res.getColorStateList(R.color.green);
this.blue = res.getColorStateList(R.color.blue);
+
}
- public boolean isConnected(Cursor cursor) {
+ /**
+ * Check if we're connected to a terminal with the given nickname.
+ */
+ protected boolean isConnected(String nickname) {
// always disconnected if we dont have backend service
if(this.manager == null) return false;
-
- // otherwise pull out nickname and check if active
- if(COL_NICKNAME == -1)
- COL_NICKNAME = cursor.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_NICKNAME);
-
- String nickname = cursor.getString(COL_NICKNAME);
return (this.manager.findBridge(nickname) != null);
}
@@ -46,7 +70,12 @@ public class HostBinder implements ViewBinder {
case android.R.id.icon:
// set icon state based on status from backend service
ImageView icon = (ImageView)view;
- if(this.isConnected(cursor)) {
+
+ if(COL_NICKNAME == -1)
+ COL_NICKNAME = cursor.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_NICKNAME);
+
+ String nickname = cursor.getString(COL_NICKNAME);
+ if(this.isConnected(nickname)) {
icon.setImageState(new int[] { android.R.attr.state_checked }, true);
} else {
icon.setImageState(new int[] { }, true);
@@ -65,9 +94,11 @@ public class HostBinder implements ViewBinder {
if(HostDatabase.COLOR_BLUE.equals(color)) chosen = this.blue;
if(chosen != null) {
+ // set color normally if not selected
text1.setTextColor(chosen);
text2.setTextColor(chosen);
} else {
+ // selected, so revert back to default black text
text1.setTextAppearance(view.getContext(), android.R.attr.textAppearanceLarge);
text2.setTextAppearance(view.getContext(), android.R.attr.textAppearanceSmall);
}
diff --git a/src/org/connectbot/util/HostDatabase.java b/src/org/connectbot/util/HostDatabase.java
index 93c9e70..4f067dc 100644
--- a/src/org/connectbot/util/HostDatabase.java
+++ b/src/org/connectbot/util/HostDatabase.java
@@ -1,3 +1,21 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
package org.connectbot.util;
import java.util.LinkedList;
@@ -10,7 +28,12 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
-
+/**
+ * Contains information about various SSH hosts, include public hostkey if known
+ * from previous sessions.
+ *
+ * @author jsharkey
+ */
public class HostDatabase extends SQLiteOpenHelper {
public final static String DB_NAME = "hosts";
@@ -26,10 +49,6 @@ public class HostDatabase extends SQLiteOpenHelper {
public final static String FIELD_HOST_COLOR = "color";
public final static String FIELD_HOST_USEKEYS = "usekeys";
- public final static String TABLE_PRIVKEYS = "keys";
- public final static String FIELD_KEY_NAME = "name";
- public final static String FIELD_KEY_PRIVATE = "private";
-
public final static String COLOR_RED = "red";
public final static String COLOR_GREEN = "green";
public final static String COLOR_BLUE = "blue";
@@ -52,11 +71,7 @@ public class HostDatabase extends SQLiteOpenHelper {
+ FIELD_HOST_COLOR + " TEXT, "
+ FIELD_HOST_USEKEYS + " TEXT)");
- db.execSQL("CREATE TABLE " + TABLE_PRIVKEYS
- + " (_id INTEGER PRIMARY KEY, "
- + FIELD_KEY_NAME + " TEXT, "
- + FIELD_KEY_PRIVATE + " TEXT)");
-
+ // insert a few sample hosts, none of which probably connect
this.createHost(db, "connectbot@bravo", "connectbot", "192.168.254.230", 22, null);
this.createHost(db, "root@google.com", "root", "google.com", 22, null);
this.createHost(db, "cron@server.example.com", "cron", "server.example.com", 22, COLOR_BLUE);
@@ -67,14 +82,15 @@ public class HostDatabase extends SQLiteOpenHelper {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_HOSTS);
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_PRIVKEYS);
onCreate(db);
}
+ /**
+ * Touch a specific host to update its "last connected" field.
+ * @param nickname Nickname field of host to update
+ */
public void touchHost(String nickname) {
- Log.w(this.getClass().toString(), String.format("touchHost(nickname=%s)", nickname));
-
SQLiteDatabase db = this.getWritableDatabase();
long now = System.currentTimeMillis() / 1000;
@@ -86,6 +102,10 @@ public class HostDatabase extends SQLiteOpenHelper {
}
+ /**
+ * Create a new host using the given parameters, and return its new
+ * <code>_id</code> value.
+ */
public long createHost(SQLiteDatabase db, String nickname, String username, String hostname, int port, String color) {
// create and insert new host
@@ -105,6 +125,9 @@ public class HostDatabase extends SQLiteOpenHelper {
}
+ /**
+ * Delete a specific host by its <code>_id</code> value.
+ */
public void deleteHost(long id) {
SQLiteDatabase db = this.getWritableDatabase();
@@ -112,6 +135,10 @@ public class HostDatabase extends SQLiteOpenHelper {
}
+ /**
+ * Return a cursor that contains information about all known hosts.
+ * @param sortColors If true, sort by color, otherwise sort by nickname.
+ */
public Cursor allHosts(boolean sortColors) {
String sortField = sortColors ? FIELD_HOST_COLOR : FIELD_HOST_NICKNAME;
diff --git a/src/org/connectbot/util/KeyDatabase.java b/src/org/connectbot/util/KeyDatabase.java
new file mode 100644
index 0000000..a3d48f9
--- /dev/null
+++ b/src/org/connectbot/util/KeyDatabase.java
@@ -0,0 +1,65 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package org.connectbot.util;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+/**
+ * Contains information about personal private keys used for key-based
+ * authentication. Find more information here:
+ *
+ * http://www.wlug.org.nz/PublicKeyAuthentication
+ *
+ * @author jsharkey
+ */
+public class KeyDatabase extends SQLiteOpenHelper {
+
+ public final static String DB_NAME = "keys";
+ public final static int DB_VERSION = 1;
+
+ public final static String TABLE_PRIVKEYS = "keys";
+ public final static String FIELD_KEY_NAME = "name";
+ public final static String FIELD_KEY_PRIVATE = "private";
+
+ public KeyDatabase(Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_PRIVKEYS
+ + " (_id INTEGER PRIMARY KEY, "
+ + FIELD_KEY_NAME + " TEXT, "
+ + FIELD_KEY_PRIVATE + " TEXT)");
+
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_PRIVKEYS);
+ onCreate(db);
+ }
+
+
+}
diff --git a/src/org/connectbot/util/UpdateHelper.java b/src/org/connectbot/util/UpdateHelper.java
new file mode 100644
index 0000000..b74676f
--- /dev/null
+++ b/src/org/connectbot/util/UpdateHelper.java
@@ -0,0 +1,185 @@
+/*
+ ConnectBot: simple, powerful, open-source SSH client for Android
+ Copyright (C) 2007-2008 Kenny Root, Jeffrey Sharkey
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package org.connectbot.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+import org.json.JSONObject;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+/**
+ * Helper class that checks for updates to this application. On construction, it
+ * spawns a background thread that checks for any app updates. If available,
+ * shows a dialog to the user, prompting them to visit Market for the upgrade.
+ *
+ * <b>Be sure to change the UPDATE_URL field before using this class.</b> Then
+ * place a text file at that URL containing JSON data in the format:
+ *
+ * <code>{"versionCode": 110, "features": "Brand new interface with over
+ * 9,000 improvements.", "target": "search?q=searchterms"}</code>
+ *
+ * Which should contain information about your newest version. The
+ * <code>target</code> field is used to build an Intent that launches Market on
+ * the device, simply be prefixing it with <code>market://</code>. If you know
+ * your exact Market ID, you could use the value
+ * <code>details?id=yourexactmarketid</code>
+ *
+ * If you're looking for an advanced version-checking system that offers more
+ * customization, check out Veecheck: http://www.tomgibara.com/android/veecheck/
+ *
+ * @author jsharkey
+ */
+public class UpdateHelper implements Runnable {
+
+ public final static String TAG = UpdateHelper.class.toString();
+ public final static String UPDATE_URL = "http://connectbot.org/version";
+
+ protected Context context;
+
+ protected String packageName, versionName;
+ protected int versionCode;
+
+ protected String userAgent;
+
+ /**
+ * Constructor will automatically spawn thread to check for updates.
+ * Recommended usage is <code>new UpdateHelper(this);</code> in the first
+ * onCreate() of your app.
+ */
+ public UpdateHelper(Context context) {
+ this.context = context;
+
+ try {
+ // read current version information about this package
+ PackageManager manager = context.getPackageManager();
+ PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
+ this.packageName = info.packageName;
+ this.versionCode = info.versionCode;
+ this.versionName = info.versionName;
+
+ } catch(Exception e) {
+ Log.e(TAG, "Couldn't find package information in PackageManager", e);
+ return;
+
+ }
+
+ // place version information in user-agent string to be used later
+ this.userAgent = String.format("%s/%s (%d)", packageName, versionName, versionCode);
+
+ // spawn thread to check for update
+ new Thread(this).start();
+
+ }
+
+ public void run() {
+ try {
+ // fetch and parse the version update information as json
+ // pass information off to handler to create
+ JSONObject json = new JSONObject(UpdateHelper.getUrl(UPDATE_URL, userAgent));
+ Message.obtain(versionHandler, -1, json).sendToTarget();
+
+ } catch(Exception e) {
+ Log.e(TAG, "Problem while fetching/parsing update response", e);
+
+ }
+ }
+
+
+ /**
+ * Handler that will parse the JSON response and show dialog to user if an
+ * update is available.
+ */
+ public Handler versionHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+
+ // make sure we are being passed a real json object
+ if(!(msg.obj instanceof JSONObject)) return;
+ JSONObject json = (JSONObject)msg.obj;
+
+ // pull out version and target information from response
+ final int versionCode = json.optInt("versionCode");
+ final String features = json.optString("features");
+ final String target = "market://" + json.optString("target");
+
+ // skip if we're already good enough
+ if(versionCode <= UpdateHelper.this.versionCode) return;
+
+ // build dialog to prompt user about updating
+ new AlertDialog.Builder(context)
+ .setTitle("New version")
+ .setMessage(features)
+ .setPositiveButton("Yes, upgrade", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(target));
+ context.startActivity(intent);
+ }
+ })
+ .setNegativeButton("Not right now", null).create().show();
+
+ }
+
+
+ };
+
+ /**
+ * Read contents of a URL and return as a String. Handles any server
+ * downtime with a 6-second timeout.
+ */
+ public static String getUrl(String tryUrl, String userAgent) throws Exception {
+
+ URL url = new URL(tryUrl);
+ URLConnection connection = url.openConnection();
+ connection.setConnectTimeout(6000);
+ connection.setReadTimeout(6000);
+ connection.setRequestProperty("User-Agent", userAgent);
+ connection.connect();
+
+ InputStream is = connection.getInputStream();
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ int bytesRead;
+ byte[] buffer = new byte[1024];
+ while ((bytesRead = is.read(buffer)) != -1) {
+ os.write(buffer, 0, bytesRead);
+ }
+
+ os.flush();
+ os.close();
+ is.close();
+
+ return new String(os.toByteArray());
+
+ }
+
+
+}
diff --git a/src/org/theb/provider/HostDb.java b/src/org/theb/provider/HostDb.java
deleted file mode 100644
index 1ed7c0c..0000000
--- a/src/org/theb/provider/HostDb.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.provider;
-
-
-import android.net.Uri;
-import android.provider.BaseColumns;
-
-public final class HostDb {
- public static final class Hosts implements BaseColumns {
- public static final Uri CONTENT_URI
- = Uri.parse("content://org.theb.provider.HostDb/hosts");
-
- public static final String DEFAULT_SORT_ORDER = "nickname DESC";
-
- public static final String NICKNAME = "nickname";
- public static final String USERNAME = "username";
- public static final String HOSTNAME = "hostname";
- public static final String PORT = "port";
- public static final String EMULATION = "emulation";
- public static final String SCROLLBACK = "scrollback";
- public static final String HOSTKEY = "hostkey";
- }
-}
diff --git a/src/org/theb/ssh/ConnectionThread.java b/src/org/theb/ssh/ConnectionThread.java
deleted file mode 100644
index a201e62..0000000
--- a/src/org/theb/ssh/ConnectionThread.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public abstract class ConnectionThread extends Thread {
- public ConnectionThread(FeedbackUI ui, String hostname, String username, int port) {}
- public abstract void finish();
- public abstract InputStream getReader();
- public abstract OutputStream getWriter();
- public abstract void setPassword(String password);
-}
diff --git a/src/org/theb/ssh/FeedbackUI.java b/src/org/theb/ssh/FeedbackUI.java
deleted file mode 100644
index ba4ae03..0000000
--- a/src/org/theb/ssh/FeedbackUI.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-public interface FeedbackUI {
- public void connectionLost(Throwable reason);
- public void setWaiting(boolean isWaiting, String title, String message);
- public void askPassword();
-}
diff --git a/src/org/theb/ssh/HostDbProvider.java b/src/org/theb/ssh/HostDbProvider.java
deleted file mode 100644
index f3bdbd5..0000000
--- a/src/org/theb/ssh/HostDbProvider.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import java.util.HashMap;
-
-import org.theb.provider.HostDb;
-
-import android.content.ContentProvider;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.UriMatcher;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.database.sqlite.SQLiteDatabase.CursorFactory;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.util.Log;
-
-public class HostDbProvider extends ContentProvider {
-
- private SQLiteDatabase mDB;
-
- private static final String TAG = "HostDbProvider";
- private static final String DATABASE_NAME = "ssh_hosts.db";
- private static final int DATABASE_VERSION = 3;
-
- private static HashMap<String, String> HOSTS_LIST_PROJECTION_MAP;
-
- private static final int HOSTS = 1;
- private static final int HOST_ID = 2;
-
- private static final UriMatcher URL_MATCHER;
-
- private static class DatabaseHelper extends SQLiteOpenHelper {
-
- public DatabaseHelper(Context context, String name,
- CursorFactory factory, int version) {
- super(context, name, factory, version);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE hosts (_id INTEGER PRIMARY KEY," +
- "nickname TEXT," +
- "hostname TEXT," +
- "username TEXT," +
- "port INTEGER," +
- "emulation TEXT," +
- "scrollback INTEGER," +
- "hostkey TEXT" +
- ")");
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
- + newVersion + ", which will destroy all old data");
- db.execSQL("DROP TABLE IF EXISTS hosts");
- onCreate(db);
- }
-
- }
-
- @Override
- public int delete(Uri uri, String where, String[] whereArgs) {
- int count;
- switch (URL_MATCHER.match(uri)) {
- case HOSTS:
- count = mDB.delete("ssh_hosts", where, whereArgs);
- break;
-
- case HOST_ID:
- String segment = uri.getPathSegments().get(1);
- count = mDB.delete("hosts", "_id="
- + segment
- + (!TextUtils.isEmpty(where) ? " AND (" + where
- + ')' : ""), whereArgs);
- break;
-
- default:
- throw new IllegalArgumentException("Unknown Delete " + uri);
- }
-
- getContext().getContentResolver().notifyChange(uri, null);
- return count;
- }
-
- @Override
- public String getType(Uri uri) {
- switch (URL_MATCHER.match(uri)) {
- case HOSTS:
- return "vnd.android.cursor.dir/vnd.theb.host";
- case HOST_ID:
- return "vnd.android.cursor.item/vnd.theb.host";
- default:
- throw new IllegalArgumentException("Unknown getType " + uri);
- }
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues initialValues) {
- long rowID;
-
- ContentValues values;
- if (initialValues != null) {
- values = new ContentValues(initialValues);
- } else {
- values = new ContentValues();
- }
- /*
- if (URL_MATCHER.match(uri) != HOSTS) {
- throw new IllegalArgumentException("Unknown Insert " + uri);
- }
- */
- if (values.containsKey(HostDb.Hosts.NICKNAME) == false) {
- values.put(HostDb.Hosts.NICKNAME, "");
- }
-
- if (values.containsKey(HostDb.Hosts.HOSTNAME) == false) {
- values.put(HostDb.Hosts.HOSTNAME, "");
- }
-
- if (values.containsKey(HostDb.Hosts.USERNAME) == false) {
- values.put(HostDb.Hosts.USERNAME, "");
- }
-
- if (values.containsKey(HostDb.Hosts.PORT) == false) {
- values.put(HostDb.Hosts.PORT, 22);
- }
-
- if (values.containsKey(HostDb.Hosts.HOSTKEY) == false) {
- values.put(HostDb.Hosts.HOSTKEY, "");
- }
-
- if (values.containsKey(HostDb.Hosts.EMULATION) == false) {
- values.put(HostDb.Hosts.EMULATION, "");
- }
-
- if (values.containsKey(HostDb.Hosts.SCROLLBACK) == false) {
- values.put(HostDb.Hosts.SCROLLBACK, "");
- }
-
- rowID = mDB.insert("hosts", "host", values);
- if (rowID > 0) {
- Uri newUri = ContentUris.withAppendedId(HostDb.Hosts.CONTENT_URI, rowID);
- getContext().getContentResolver().notifyChange(newUri, null);
- return newUri;
- }
-
- throw new SQLException("Failed to insert row into " + uri);
- }
-
- @Override
- public boolean onCreate() {
- DatabaseHelper dbHelper = new DatabaseHelper(getContext(), DATABASE_NAME, null, DATABASE_VERSION);
- mDB = dbHelper.getWritableDatabase();
- return (mDB == null) ? false : true;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
-
- switch (URL_MATCHER.match(uri)) {
- case HOSTS:
- qb.setTables("hosts");
- qb.setProjectionMap(HOSTS_LIST_PROJECTION_MAP);
- break;
-
- case HOST_ID:
- qb.setTables("hosts");
- qb.appendWhere("_id=" + uri.getPathSegments().get(1));
- break;
-
- default:
- throw new IllegalArgumentException("Unknown Query " + uri);
- }
-
- String orderBy;
- if (TextUtils.isEmpty(sortOrder)) {
- orderBy = HostDb.Hosts.DEFAULT_SORT_ORDER;
- } else {
- orderBy = sortOrder;
- }
-
- Cursor c = qb.query(mDB, projection, selection, selectionArgs, null,
- null, orderBy);
- c.setNotificationUri(getContext().getContentResolver(), uri);
- return c;
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String where,
- String[] whereArgs) {
- int count;
-
- switch (URL_MATCHER.match(uri)) {
- case HOSTS:
- count = mDB.update("hosts", values, where, whereArgs);
- break;
-
- case HOST_ID:
- String segment = uri.getPathSegments().get(1);
- count = mDB
- .update("hosts", values, "_id="
- + segment
- + (!TextUtils.isEmpty(where) ? " AND (" + where
- + ')' : ""), whereArgs);
- break;
-
- default:
- throw new IllegalArgumentException("Unknown Update " + uri);
- }
-
- getContext().getContentResolver().notifyChange(uri, null);
- return count;
-
- }
-
- static {
- URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
- URL_MATCHER.addURI("org.theb.provider.HostDb", "hosts", HOSTS);
- URL_MATCHER.addURI("org.theb.provider.HostDb", "hosts/#", HOST_ID);
-
- HOSTS_LIST_PROJECTION_MAP = new HashMap<String, String>();
- HOSTS_LIST_PROJECTION_MAP.put(HostDb.Hosts._ID, "_id");
- HOSTS_LIST_PROJECTION_MAP.put(HostDb.Hosts.NICKNAME, "nickname");
- HOSTS_LIST_PROJECTION_MAP.put(HostDb.Hosts.HOSTNAME, "hostname");
- HOSTS_LIST_PROJECTION_MAP.put(HostDb.Hosts.USERNAME, "username");
- HOSTS_LIST_PROJECTION_MAP.put(HostDb.Hosts.PORT, "port");
- HOSTS_LIST_PROJECTION_MAP.put(HostDb.Hosts.HOSTKEY, "hostkey");
- HOSTS_LIST_PROJECTION_MAP.put(HostDb.Hosts.EMULATION, "emulation");
- HOSTS_LIST_PROJECTION_MAP.put(HostDb.Hosts.SCROLLBACK, "scrollback");
- }
-}
diff --git a/src/org/theb/ssh/HostEditor.java b/src/org/theb/ssh/HostEditor.java
deleted file mode 100644
index 128d827..0000000
--- a/src/org/theb/ssh/HostEditor.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import org.connectbot.R;
-import org.theb.provider.HostDb;
-import org.theb.provider.HostDb.Hosts;
-
-import android.app.Activity;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.EditText;
-import android.widget.Spinner;
-
-public class HostEditor extends Activity {
- public static final String EDIT_HOST_ACTION = "org.theb.ssh.action.EDIT_HOST";
-
- private static final String[] PROJECTION = new String[] { HostDb.Hosts._ID,
- HostDb.Hosts.NICKNAME, HostDb.Hosts.HOSTNAME,
- HostDb.Hosts.USERNAME, HostDb.Hosts.PORT, HostDb.Hosts.EMULATION,
- HostDb.Hosts.SCROLLBACK, };
-
- private static final int INDEX_NICKNAME = 1, INDEX_HOSTNAME = 2,
- INDEX_USERNAME = 3, INDEX_PORT = 4, INDEX_EMULATION = 5,
- INDEX_SCROLLBACK = 6;
-
- // Set up distinct states that the activity can be run in.
- private static final int STATE_EDIT = 0;
- private static final int STATE_INSERT = 1;
-
- private EditText mNickname, mHostname, mUsername, mPort, mScrollback;
- private Spinner mEmulation;
-
- // Cursor that will provide access to the host data we are editing
- private Cursor mCursor;
-
- private int mState;
- private Uri mURI;
-
- @Override
- public void onCreate(Bundle savedValues) {
- super.onCreate(savedValues);
- this.setContentView(R.layout.act_hosteditor);
-
- // Set up click handlers for text fields and button
- this.mNickname = (EditText) findViewById(R.id.edit_nickname);
- this.mHostname = (EditText) findViewById(R.id.edit_hostname);
- this.mUsername = (EditText) findViewById(R.id.edit_username);
- this.mPort = (EditText) findViewById(R.id.edit_port);
- this.mEmulation = (Spinner) findViewById(R.id.edit_emulation);
- this.mScrollback = (EditText) findViewById(R.id.edit_scrollback);
-
- // Do some setup based on the action being performed.
- final Intent intent = getIntent();
- final String action = intent.getAction();
-
- if (Intent.ACTION_INSERT.equals(action)) {
- mState = STATE_INSERT;
- mURI = getContentResolver().insert(intent.getData(), null);
-
- // If we were unable to create a new note, then just finish
- // this activity. A RESULT_CANCELED will be sent back to the
- // original activity if they requested a result.
- if (mURI == null) {
- Log.e("SSH", "Failed to insert new host into " + getIntent().getData());
- finish();
- return;
- }
-
- // The new entry was created, so assume all will end well and
- // set the result to be returned.
- intent.putExtra(Intent.EXTRA_TEXT, mURI.toString());
- setResult(RESULT_OK, intent);
- } else {
- // Editing is the default state.
- mState = STATE_EDIT;
-
- // Get the URI of the host whose properties we want to edit
- mURI = getIntent().getData();
- }
-
- // Get a cursor to access the host data
- //this.mCursor = managedQuery(mURI, PROJECTION, null, null);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- // Initialize the text with the host data
- if(mCursor != null) {
- mCursor.moveToFirst();
-
- this.mNickname.setText(mCursor.getString(HostEditor.INDEX_NICKNAME));
- this.mHostname.setText(mCursor.getString(HostEditor.INDEX_HOSTNAME));
- this.mUsername.setText(mCursor.getString(HostEditor.INDEX_USERNAME));
- this.mPort.setText(mCursor.getString(HostEditor.INDEX_PORT));
- //this.emulation.setText(cursor.getString(this.INDEX_EMULATION));
- this.mScrollback.setText(mCursor.getString(HostEditor.INDEX_SCROLLBACK));
-
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
-
- // Write the text back into the cursor
- if(mCursor != null) {
- ContentValues values = new ContentValues();
- values.put(Hosts.NICKNAME, mNickname.getText().toString());
- values.put(Hosts.HOSTNAME, mHostname.getText().toString());
- values.put(Hosts.USERNAME, mUsername.getText().toString());
- //mEmulation.getSelectedItemPosition();
- int port;
- try {
- port = Integer.parseInt(mPort.getText().toString());
- } catch (Exception e) {
- port = 22;
- }
- values.put(Hosts.PORT, port);
-
- int scrollback;
- try {
- scrollback = Integer.parseInt(mScrollback.getText().toString());
- } catch (Exception e) {
- scrollback = 1000; // TODO: grab from R.whatever
- }
- values.put(Hosts.SCROLLBACK, scrollback);
-
- getContentResolver().update(mURI, values, null, null);
- }
- }
-
- private final void cancelEdit() {
- if (mCursor != null) {
- if (mState == STATE_EDIT) {
- mCursor.deactivate();
- mCursor = null;
- } else if (mState == STATE_INSERT) {
- deleteHost();
- }
- }
- }
-
- private final void deleteHost() {
- if (mCursor != null) {
- mHostname.setText("");
- mUsername.setText("");
- mPort.setText("");
- getContentResolver().delete(mURI, null, null);
- mCursor.deactivate();
- mCursor = null;
- }
- }
-
-}
diff --git a/src/org/theb/ssh/HostsList.java b/src/org/theb/ssh/HostsList.java
deleted file mode 100644
index 888d629..0000000
--- a/src/org/theb/ssh/HostsList.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import java.util.concurrent.Semaphore;
-
-import org.connectbot.Console;
-import org.connectbot.service.TerminalBridge;
-import org.connectbot.service.TerminalManager;
-import org.connectbot.R;
-import org.theb.provider.HostDb;
-
-import com.trilead.ssh2.Connection;
-
-import android.app.Dialog;
-import android.app.ListActivity;
-import android.content.ComponentName;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.View.MeasureSpec;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
-
-public class HostsList extends ListActivity {
- public static final int CONNECT_ID = Menu.FIRST;
- public static final int EDIT_ID = Menu.FIRST + 1;
- public static final int DELETE_ID = Menu.FIRST + 2;
- public static final int INSERT_ID = Menu.FIRST + 3;
- public static final int PREFERENCES_ID = Menu.FIRST + 4;
- public static final int ABOUT_ID = Menu.FIRST + 5;
-
- // Preferences submenu
- public static final int PUBKEY_ID = SubMenu.FIRST + 4;
-
- private static final String[] PROJECTION = new String[] {
- HostDb.Hosts._ID,
- HostDb.Hosts.HOSTNAME,
- HostDb.Hosts.USERNAME,
- HostDb.Hosts.PORT,
- HostDb.Hosts.NICKNAME
- };
-
- private Cursor mCursor;
-
- /**
- * @author kenny
- * Imparts a more informative view of the host list.
- *
- * Displays as "username@hostname:port" but only includes the port if it is
- * not on the default port 22.
- */
- public class HostListCursorAdapter extends SimpleCursorAdapter {
-
- public HostListCursorAdapter(Context context, int layout, Cursor c,
- String[] from, int[] to) {
- super(context, layout, c, from, to);
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- String label;
- TextView textView = (TextView) view;
-
-// label = cursor.getString(2) + "@" + cursor.getString(1);
-// int port = cursor.getInt(3);
-// if (port != 22) {
-// label = label + ":" + String.valueOf(port);
-// }
-
- label = cursor.getString(4);
- textView.setText(label);
- }
-
- }
-
- public TerminalManager bound = null;
-
- private ServiceConnection connection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(this.getClass().toString(), "yay we bound to our terminalmanager");
- bound = ((TerminalManager.TerminalBinder) service).getService();
-
- // TODO: update our green bulb icons by checking for existing bridges
- // open up some test sessions
-// try {
-// bound.openConnection("192.168.254.230", 22, "connectbot", "b0tt", "screen", 100);
-// bound.openConnection("192.168.254.230", 22, "connectbot", "b0tt", "screen", 100);
-// bound.openConnection("192.168.254.230", 22, "connectbot", "b0tt", "screen", 100);
-// } catch(Exception e) {
-// e.printStackTrace();
-// }
-
- }
-
- public void onServiceDisconnected(ComponentName className) {
- Log.d(this.getClass().toString(), "oops our terminalmanager was lost");
- bound = null;
- }
- };
-
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- // start the terminal manager service and bind locally
- this.startService(new Intent(this, TerminalManager.class));
- this.bindService(new Intent(this, TerminalManager.class), connection, Context.BIND_AUTO_CREATE);
-
-
- //setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
-
- Intent intent = getIntent();
- if (intent.getData() == null) {
- intent.setData(HostDb.Hosts.CONTENT_URI);
- }
-
- //setupListStripes();
-
- //mCursor = managedQuery(getIntent().getData(), PROJECTION, null, null);
-
- ListAdapter adapter = new HostListCursorAdapter(this,
- android.R.layout.simple_list_item_1, mCursor,
- new String[] {HostDb.Hosts.HOSTNAME}, new int[] {android.R.id.text1});
-
- setListAdapter(adapter);
- }
-
-// /**
-// * Add stripes to the list view.
-// */
-// private void setupListStripes() {
-// // Get Drawables for alternating stripes
-// Drawable[] lineBackgrounds = new Drawable[2];
-//
-// lineBackgrounds[0] = getResources().getDrawable(R.drawable.even_stripe);
-// lineBackgrounds[1] = getResources().getDrawable(R.drawable.odd_stripe);
-//
-// // Make and measure a sample TextView of the sort our adapter will
-// // return
-// View view = getViewInflate().inflate(
-// android.R.layout.simple_list_item_1, null, null);
-//
-// TextView v = (TextView) view.findViewById(android.R.id.text1);
-// v.setText("X");
-// // Make it 100 pixels wide, and let it choose its own height.
-// v.measure(MeasureSpec.makeMeasureSpec(View.MeasureSpec.EXACTLY, 100),
-// MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, 0));
-// int height = v.getMeasuredHeight();
-// getListView().setStripes(lineBackgrounds, height);
-// }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
-
- // This is our one standard application action -- inserting a
- // new host into the list.
- menu.add(0, INSERT_ID, INSERT_ID, R.string.menu_insert)
- .setShortcut('3', 'a');
-
- // The preferences link allows users to e.g. set the pubkey
- SubMenu prefs = menu.addSubMenu(0, 0, PREFERENCES_ID, R.string.menu_preferences);
- prefs.add(0, PUBKEY_ID, Menu.NONE, R.string.menu_pubkey)
- .setShortcut('4', 'p');
-
- // This links to the about dialog for the program.
- menu.add(0, ABOUT_ID, ABOUT_ID, R.string.menu_about);
-
- // Generate any additional actions that can be performed on the
- // overall list. In a normal install, there are no additional
- // actions found here, but this allows other applications to extend
- // our menu with their own actions.
- Intent intent = new Intent(null, getIntent().getData());
- intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
- menu.addIntentOptions(
- Menu.CATEGORY_ALTERNATIVE, 0, Menu.NONE, new ComponentName(this, HostsList.class),
- null, intent, 0, null);
-
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
- final boolean haveItems = mCursor.getCount() > 0;
-
- // If there are any notes in the list (which does not necessarily imply one of
- // them is selected), then we need to generate the actions that
- // can be performed on the current selection. This will be a combination
- // of our own specific actions along with any extensions that can be
- // found.
- if (haveItems && getSelectedItemId() >= 0) {
- // This is the selected item.
- Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId());
-
- // Build menu... always starts with the PICK action...
- Intent[] specifics = new Intent[1];
- specifics[0] = new Intent(Intent.ACTION_PICK, uri);
- MenuItem[] items = new MenuItem[1];
-
- // ... is followed by whatever other actions are available...
- Intent intent = new Intent(null, uri);
- intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
- menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, Menu.NONE, null, specifics,
- intent, 0, items);
-
- // ... and ends with the delete command.
- menu.add(Menu.CATEGORY_ALTERNATIVE, DELETE_ID, DELETE_ID, R.string.menu_delete)
- .setShortcut('2', 'd');
-
- // Give a shortcut to the connect action.
- if (items[0] != null) {
- items[0].setShortcut('1', 'c');
- }
- } else {
- menu.removeGroup(Menu.CATEGORY_ALTERNATIVE);
- }
-
- // Make sure the delete action is disabled if there are no items.
- //menu.setItemShown(DELETE_ID, haveItems);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case DELETE_ID:
- deleteItem();
- return true;
- case INSERT_ID:
- insertItem();
- return true;
- case PUBKEY_ID:
- showPubkey();
- return true;
- case ABOUT_ID:
- showAbout();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private void showPubkey() {
- Intent intent = new Intent(this, Pubkey.class);
- this.startActivity(intent);
- }
-
- private void showAbout() {
- Dialog about = new Dialog(this);
- //about.setContentView(R.layout.about_dialog);
- about.setTitle(getResources().getString(R.string.app_name)
- + " "
- + getResources().getString(R.string.msg_version));
-
- // TODO: update or remove
- // Everything looks cooler when you blur the window behind it.
- //about.getWindow().setFlags(WindowManager.LayoutParams.BLUR_BEHIND_FLAG,
- // WindowManager.LayoutParams.BLUR_BEHIND_FLAG);
- WindowManager.LayoutParams lp = about.getWindow().getAttributes();
- //lp.tintBehind = 0x60000820;
- about.getWindow().setAttributes(lp);
-
- about.show();
- }
-
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- Uri url = ContentUris.withAppendedId(getIntent().getData(), id);
-
- String action = getIntent().getAction();
- if (Intent.ACTION_PICK.equals(action)
- || Intent.ACTION_GET_CONTENT.equals(action)) {
- // The caller is waiting for us to return a note selected by
- // the user. The have clicked on one, so return it now.
- Intent intent = this.getIntent();
- intent.putExtra(Intent.EXTRA_TEXT, url.toString());
- setResult(RESULT_OK, intent);
- } else {
- // Launch activity to view/edit the currently selected item
- //startActivity(new Intent(Intent.ACTION_PICK, url));
-
- // collect all connection details
- Cursor cursor = null;
-// managedQuery(url, new String[] { "nickname",
-// "username", "hostname", "port", "emulation", "scrollback",
-// "hostkey" }, null, null);
- cursor.moveToFirst();
-
- // try finding an already-open bridge for this connection
- final String nickname = cursor.getString(0);
- TerminalBridge bridge = bound.findBridge(nickname);
- if(bridge == null) {
- // too bad, looks like we have to open the bridge ourselves
- final String username = cursor.getString(1);
- final String hostname = cursor.getString(2);
- final int port = cursor.getInt(3);
- final String emulation = cursor.getString(4);
- final int scrollback = cursor.getInt(5);
- final String hostkey = cursor.getString(6);
-
- try {
- // TODO: this is horridly messy lol
- // TODO: finish copying over logic from TrileadConnectionThread here
-
- this.startActivityForResult(new Intent(this, PasswordDialog.class), PASSWORD_REQUEST);
-
- Thread connect = new Thread(new Runnable() {
-
- public void run() {
- try {
- waitPassword.acquire();
- //Connection conn;
- //bound.openConnection(conn, nickname, emulation, scrollback);
- if (password != null) {
- //bound.openConnection(nickname, hostname, port, username, password, "screen", 100);
-
- // open the console view and select this specific terminal
- Intent intent = new Intent(HostsList.this, Console.class);
- intent.putExtra(Intent.EXTRA_TEXT, nickname);
- startActivity(intent);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- password = null;
- }
- });
- connect.start();
-
- } catch(Exception e) {
- e.printStackTrace();
- }
-
-
- } else {
- // we found an existing terminal, so open it
- // open the console view and select this specific terminal
- Intent intent = new Intent(this, Console.class);
- intent.putExtra(Intent.EXTRA_TEXT, nickname);
- this.startActivity(intent);
- }
-
-
- }
- }
-
- public final static int PASSWORD_REQUEST = 42;
- public Semaphore waitPassword = new Semaphore(0);
- public String password = null;
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if(requestCode == PASSWORD_REQUEST) {
- if (data != null) {
- this.password = data.getStringExtra(Intent.EXTRA_TEXT);
- } else {
- this.password = null;
- }
- this.waitPassword.release();
- }
- }
-
- private final void deleteItem() {
- mCursor.move(getSelectedItemPosition());
- Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId());
- getContentResolver().delete(uri, null, null);
- }
-
- private final void insertItem() {
- // Launch activity to insert a new item
- startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));
- }
-} \ No newline at end of file
diff --git a/src/org/theb/ssh/InteractiveHostKeyVerifier.java b/src/org/theb/ssh/InteractiveHostKeyVerifier.java
deleted file mode 100644
index 7c21f80..0000000
--- a/src/org/theb/ssh/InteractiveHostKeyVerifier.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import com.trilead.ssh2.ServerHostKeyVerifier;
-
-public class InteractiveHostKeyVerifier implements ServerHostKeyVerifier {
-
- public boolean verifyServerHostKey(String hostname, int port,
- String serverHostKeyAlgorithm, byte[] serverHostKey)
- throws Exception {
- // TODO Auto-generated method stub
- return true;
- }
-
-}
diff --git a/src/org/theb/ssh/JCTerminalView.java b/src/org/theb/ssh/JCTerminalView.java
deleted file mode 100644
index b76794f..0000000
--- a/src/org/theb/ssh/JCTerminalView.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PixelXorXfermode;
-import android.graphics.Typeface;
-import android.graphics.Bitmap.Config;
-import android.graphics.Paint.FontMetricsInt;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-
-import com.jcraft.jcterm.Emulator;
-import com.jcraft.jcterm.EmulatorVT100;
-import com.jcraft.jcterm.Term;
-
-public class JCTerminalView extends View implements Term, Terminal {
- private final Paint mPaint;
- private Bitmap mBitmap;
- private Canvas mCanvas;
-
- private final Paint mCursorPaint;
-
- private Emulator emulator = null;
-
- private boolean mBold = false;
- private boolean mUnderline = false;
- private boolean mReverse = false;
-
- private int mDefaultForeground = Color.WHITE;
- private int mDefaultBackground = Color.BLACK;
- private int mForeground = Color.WHITE;
- private int mBackground = Color.BLACK;
-
- private boolean mAntialias = true;
-
- private int mTermWidth = 80;
- private int mTermHeight = 24;
-
- private int mCharHeight;
- private int mCharWidth;
- private int mDescent;
-
-
- // Cursor location
- private int x = 0;
- private int y = 0;
-
- private final Object[] mColors = {Color.BLACK, Color.RED, Color.GREEN, Color.YELLOW,
- Color.BLUE, Color.MAGENTA, Color.CYAN, Color.WHITE};
-
- public JCTerminalView(Context c) {
- super(c);
- mPaint = new Paint();
- mPaint.setAntiAlias(mAntialias);
- mPaint.setColor(mDefaultForeground);
-
- mCursorPaint = new Paint();
- mCursorPaint.setAntiAlias(mAntialias);
- mCursorPaint.setColor(mDefaultForeground);
- mCursorPaint.setXfermode(new PixelXorXfermode(mDefaultBackground));
-
- setFont(Typeface.MONOSPACE);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (mBitmap != null) {
- canvas.drawBitmap(mBitmap, 0, 0, null);
-
- if (mCharHeight > 0 && y > mCharHeight) {
- // Invert pixels for cursor position.
- canvas.drawRect(x, y - mCharHeight, x + mCharWidth, y, mCursorPaint);
- }
- }
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- Log.d("SSH/TerminalView", "onSizeChanged called");
- Bitmap newBitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
- Canvas newCanvas = new Canvas();
-
- newCanvas.setBitmap(newBitmap);
-
- if (mBitmap != null)
- newCanvas.drawBitmap(mBitmap, 0, 0, mPaint);
-
- mBitmap = newBitmap;
- mCanvas = newCanvas;
-
- setSize(w, h);
- }
-
- private void setSize(int w, int h) {
- int column = w / getCharWidth();
- int row = h / getCharHeight();
-
- mTermWidth = column;
- mTermHeight = row;
-
- if (emulator != null)
- emulator.reset();
-
- clear_area(0, 0, w, h);
-
- // TODO: finish this method
- }
-
- private void setFont(Typeface typeface) {
- mPaint.setTypeface(typeface);
- mPaint.setTextSize(8);
- FontMetricsInt fm = mPaint.getFontMetricsInt();
- mDescent = fm.descent;
-
- float[] widths = new float[1];
- mPaint.getTextWidths("X", widths);
- mCharWidth = (int)widths[0];
-
- // Is this right?
- mCharHeight = Math.abs(fm.top) + Math.abs(fm.descent);
- Log.d("SSH", "character height is " + mCharHeight);
- // mCharHeight += mLineSpace * 2;
- // mDescent += mLineSpace;
- }
-
- public void beep() {
- // TODO Auto-generated method stub
-
- }
-
- public void clear() {
- mPaint.setColor(getBackgroundColor());
- mCanvas.drawRect(0, 0, mCanvas.getWidth(),
- mCanvas.getHeight(), mPaint);
- mPaint.setColor(getForegroundColor());
- }
-
- private int getBackgroundColor() {
- if (mReverse)
- return mForeground;
- return mBackground;
- }
-
- private int getForegroundColor() {
- if (mReverse)
- return mBackground;
- return mForeground;
- }
-
- public void clear_area(int x1, int y1, int x2, int y2) {
- mPaint.setColor(getBackgroundColor());
- if (mCanvas != null)
- mCanvas.drawRect(x1, y1, x2, y2, mPaint);
- mPaint.setColor(getForegroundColor());
- }
-
- public void drawBytes(byte[] buf, int s, int len, int x, int y) {
- String chars = null;
- try {
- chars = new String(buf, "ASCII");
- drawString(chars.substring(s, s+len), x, y);
- } catch (UnsupportedEncodingException e) {
- // TODO Auto-generated catch block
- Log.e("SSH", "Can't convert bytes to ASCII");
- }
- }
-
- public void drawString(String str, int x, int y) {
- mPaint.setFakeBoldText(mBold);
- mPaint.setUnderlineText(mUnderline);
- mCanvas.drawText(str, x, y - mDescent, mPaint);
- }
-
- public void draw_cursor() {
- postInvalidate();
- }
-
- public int getCharHeight() {
- return mCharHeight;
- }
-
- public int getCharWidth() {
- return mCharWidth;
- }
-
- public Object getColor(int index) {
- if (mColors == null || index < 0 || mColors.length <= index)
- return null;
- return mColors[index];
- }
-
- public int getColumnCount() {
- return mTermWidth;
- }
-
- public int getRowCount() {
- return mTermHeight;
- }
-
- public int getTermHeight() {
- return mTermHeight * mCharHeight;
- }
-
- public int getTermWidth() {
- return mTermWidth * mCharWidth;
- }
-
- public void redraw(int x, int y, int width, int height) {
- //invalidate(x, y, x+width, y+height);
- postInvalidate();
- }
-
- public void resetAllAttributes() {
- mBold = false;
- mUnderline = false;
- mReverse = false;
-
- mBackground = mDefaultBackground;
- mForeground = mDefaultForeground;
-
- if (mPaint != null)
- mPaint.setColor(mForeground);
- }
-
- public void scroll_area(int x, int y, int w, int h, int dx, int dy) {
- // TODO: make scrolling more efficient (memory-wise)
- mCanvas.drawBitmap(Bitmap.createBitmap(mBitmap, x, y, w, h), x+dx, y+dy, null);
- }
-
- private int toColor(Object o) {
- if (o instanceof Integer) {
- return ((Integer)o).intValue();
- }
-
- if (o instanceof String) {
- return Color.parseColor((String)o);
- }
-
- return Color.WHITE;
- }
-
- public void setBackGround(Object background) {
- mBackground = toColor(background);
- }
-
- public void setBold() {
- mBold = true;
- }
-
- public void setCursor(int x, int y) {
- // Make sure we don't go outside the bounds of the window.
- this.x = Math.max(
- Math.min(x, getWidth() - mCharWidth),
- 0);
- this.y = Math.max(
- Math.min(y, getHeight()),
- mCharHeight);
- }
-
- public void setDefaultBackGround(Object background) {
- mDefaultBackground = toColor(background);
- }
-
- public void setDefaultForeGround(Object foreground) {
- mDefaultForeground = toColor(foreground);
- }
-
- public void setForeGround(Object foreground) {
- mForeground = toColor(foreground);
- }
-
- public void setReverse() {
- mReverse = true;
- if (mPaint != null)
- mPaint.setColor(getForegroundColor());
- }
-
- public void setUnderline() {
- mUnderline = true;
- }
-
- public void start(InputStream in, OutputStream out) {
- emulator = new EmulatorVT100(this, in);
- emulator.reset();
- emulator.start();
-
- clear();
- }
-
- public byte[] getKeyCode(int keyCode, int meta) {
- if (keyCode == KeyEvent.KEYCODE_ENTER)
- return emulator.getCodeENTER();
- else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT)
- return emulator.getCodeLEFT();
- else if (keyCode == KeyEvent.KEYCODE_DPAD_UP)
- return emulator.getCodeUP();
- else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
- return emulator.getCodeDOWN();
- else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT)
- return emulator.getCodeRIGHT();
- else
- return null;
- }
-}
diff --git a/src/org/theb/ssh/JTATerminalView.java b/src/org/theb/ssh/JTATerminalView.java
deleted file mode 100644
index c28e609..0000000
--- a/src/org/theb/ssh/JTATerminalView.java
+++ /dev/null
@@ -1,375 +0,0 @@
-package org.theb.ssh;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import de.mud.terminal.SoftFont;
-import de.mud.terminal.VDUBuffer;
-import de.mud.terminal.VDUDisplay;
-import de.mud.terminal.vt320;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PixelXorXfermode;
-import android.graphics.Typeface;
-import android.graphics.Bitmap.Config;
-import android.graphics.Paint.FontMetricsInt;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-
-public class JTATerminalView extends View implements VDUDisplay, Terminal, Runnable {
- private Paint paint;
- private Paint cursorPaint;
-
- private Canvas canvas;
- private Bitmap bitmap;
-
- protected vt320 emulation;
- private VDUBuffer buffer;
-
- private InputStream in;
- private OutputStream out;
-
- private String encoding = "ASCII";
- private SoftFont sf = new SoftFont();
-
- private Thread reader = null;
-
- private int charWidth;
- private int charHeight;
- private int charDescent;
-
- private int xoffset = 0;
- private int yoffset = 0;
-
- private int color[] = {
- Color.BLACK,
- Color.RED,
- Color.GREEN,
- Color.YELLOW,
- Color.BLUE,
- Color.MAGENTA,
- Color.CYAN,
- Color.WHITE,
- };
-
- private final static int COLOR_FG_STD = 7;
- private final static int COLOR_BG_STD = 0;
-
- public JTATerminalView(Context context) {
- super(context);
-
- paint = new Paint();
- paint.setAntiAlias(true);
-
- cursorPaint = new Paint();
- cursorPaint.setAntiAlias(true);
- cursorPaint.setColor(darken(color[COLOR_FG_STD]));
- cursorPaint.setXfermode(new PixelXorXfermode(color[COLOR_BG_STD]));
-
- setFont(Typeface.MONOSPACE, 10);
-
- emulation = new vt320() {
- public void write(byte[] b) {
- try {
- JTATerminalView.this.write(b);
- } catch (IOException e) {
- Log.e("SSH", "couldn't write" + b.toString());
- reader = null;
- }
- }
-
- public void sendTelnetCommand(byte cmd) {
- // TODO: implement telnet command sending
- }
-
- public void setWindowSize(int c, int r) {
- // TODO: implement window sizing
- }
- };
-
- setVDUBuffer(emulation);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- if (bitmap != null) {
- canvas.drawBitmap(bitmap, 0, 0, null);
-
- if (buffer.isCursorVisible() &&
- (buffer.screenBase + buffer.getCursorRow() >= buffer.windowBase &&
- buffer.screenBase + buffer.getCursorRow() < buffer.windowBase + buffer.height)) {
- int x = buffer.getCursorColumn() * charWidth + xoffset;
- int y = (buffer.getCursorRow() + buffer.screenBase - buffer.windowBase) * charHeight + yoffset;
- canvas.drawRect(x, y, x + charWidth, y + charHeight, cursorPaint);
- }
- }
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- Log.d("SSH/TerminalView", "onSizeChanged called");
- Bitmap newBitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
- Canvas newCanvas = new Canvas();
-
- newCanvas.setBitmap(newBitmap);
-
- if (bitmap != null)
- newCanvas.drawBitmap(bitmap, 0, 0, paint);
-
- bitmap = newBitmap;
- canvas = newCanvas;
-
- setSize(w, h);
-
- // Make sure the buffer is in the center of the screen.
- xoffset = (getWidth() - buffer.width * charWidth) / 2;
- yoffset = (getHeight() - buffer.height * charHeight) / 2;
- }
-
- private void setSize(int w, int h) {
- int termWidth = w / charWidth;
- int termHeight = h / charHeight;
-
- buffer.setScreenSize(termWidth, buffer.height = termHeight, true);
- }
-
- private void setFont(Typeface typeface, int size) {
- paint.setTypeface(typeface);
- paint.setTextSize(size);
-
- FontMetricsInt fm = paint.getFontMetricsInt();
-
- charDescent = fm.descent;
-
- float[] widths = new float[1];
- paint.getTextWidths("X", widths);
- charWidth = (int)widths[0];
-
- charHeight = Math.abs(fm.top) + Math.abs(fm.descent);
- }
-
- public void write(byte[] b) throws IOException {
- Log.e("SSH/JTATerm/write", "Trying to write" + b.toString());
- out.write(b);
- }
-
- public int getColumnCount() {
- return buffer.width;
- }
-
- public int getRowCount() {
- return buffer.height;
- }
-
- public InputStream getInput() {
- return in;
- }
-
- public byte[] getKeyCode(int keyCode, int meta) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER:
- emulation.keyTyped(vt320.KEY_ENTER, ' ', meta);
- break;
- case KeyEvent.KEYCODE_DPAD_LEFT:
- emulation.keyPressed(vt320.KEY_LEFT, ' ', meta);
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- emulation.keyPressed(vt320.KEY_UP, ' ', meta);
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- emulation.keyPressed(vt320.KEY_DOWN, ' ', meta) ;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- emulation.keyPressed(vt320.KEY_RIGHT, ' ', meta);
- break;
- }
- return null;
- }
-
- public OutputStream getOutput() {
- return out;
- }
-
- private int darken(int color) {
- return Color.argb(0xFF,
- (int)(Color.red(color) * 0.8),
- (int)(Color.green(color) * 0.8),
- (int)(Color.blue(color) * 0.8)
- );
- }
-
- /* Not used.
- private int brighten(int color) {
- return Color.argb(0xFF,
- (int)(Color.red(color) * 1.2),
- (int)(Color.green(color) * 1.2),
- (int)(Color.blue(color) * 1.2)
- );
- }
- */
-
- public void redraw() {
- // Draw the mouse-selection
- //int selectStartLine = selectBegin.y - buffer.windowBase;
- //int selectEndLine = selectEnd.y - buffer.windowBase;
-
- int fg, bg;
-
- int lines = 0;
- long time = System.currentTimeMillis() + 0;
-
- // paint.setColor(color[COLOR_BG_STD]);
- // canvas.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), paint);
- // paint.setColor(color[COLOR_FG_STD]);
-
-
- for (int l = 0; l < buffer.height; l++) {
- // Check to see if the entire buffer is dirty or if this line is dirty.
- // If neither is dirty, continue.
- if (!buffer.update[0] && !buffer.update[l + 1]) continue;
- buffer.update[l + 1] = false;
-
- lines++;
-
- // assume that we can blindly dump the terminal string
- // canvas.drawText(buffer.charArray[buffer.windowBase + l],
- // 0, buffer.charArray[buffer.windowBase + l].length,
- // 0 * charWidth + xoffset,
- // (l + 1) * charHeight - charDescent + yoffset,
- // paint);
-
-
- for (int c = 0; c < buffer.width; c++) {
- int addr = 0;
- int currAttr = buffer.charAttributes[buffer.windowBase + l][c];
-
- fg = darken(color[COLOR_FG_STD]);
- bg = darken(color[COLOR_BG_STD]);
-
- // Check if foreground color attribute is set.
- if ((currAttr & VDUBuffer.COLOR_FG) != 0)
- fg = (color[((currAttr & VDUBuffer.COLOR_FG) >> VDUBuffer.COLOR_FG_SHIFT) - 1]);
-
- // Check if background color attribute is set.
- if ((currAttr & VDUBuffer.COLOR_BG) != 0)
- bg = (darken(color[((currAttr & VDUBuffer.COLOR_BG) >> VDUBuffer.COLOR_BG_SHIFT) - 1]));
-
- // Check if bold attribute is set.
- paint.setFakeBoldText((currAttr & VDUBuffer.BOLD) != 0);
-
- if ((currAttr & VDUBuffer.LOW) != 0)
- fg = darken(fg);
-
- // Support character inversion by swapping background and foreground color.
- if ((currAttr & VDUBuffer.INVERT) != 0) {
- int swapc = bg;
- bg = fg;
- fg = swapc;
- }
-
- // If this character is in the special font, print it and continue to the next character.
- // We can't use the optimization below for special characters.
-// if (sf.inSoftFont(buffer.charArray[buffer.windowBase + l][c])) {
-// // Clear out the space where the character will be printed.
-// paint.setColor(bg);
-// canvas.drawRect(c * charWidth + xoffset, l * charHeight + yoffset,
-// c * (charWidth + 1) + xoffset, (l+1) * charHeight + yoffset, paint);
-// paint.setColor(fg);
-//
-// // FIXME: this won't work since we're not calling drawText()
-// paint.setUnderlineText((currAttr & VDUBuffer.UNDERLINE) != 0);
-//
-// // Draw the text if it's not invisible.
-// if ((currAttr & VDUBuffer.INVISIBLE) == 0)
-// sf.drawChar(canvas, paint, buffer.charArray[buffer.windowBase + l][c], xoffset + c * charWidth, l * charHeight + yoffset, charWidth, charHeight);
-// continue;
-// }
-
- // Determine the amount of continuous characters with the same settings and print them all at once.
-// while ((c + addr < buffer.width) &&
-// ((buffer.charArray[buffer.windowBase + l][c + addr] < ' ') ||
-// (buffer.charAttributes[buffer.windowBase + l][c + addr] == currAttr)) &&
-// !sf.inSoftFont(buffer.charArray[buffer.windowBase + l][c + addr])) {
-// if (buffer.charArray[buffer.windowBase + l][c + addr] < ' ') {
-// buffer.charArray[buffer.windowBase + l][c + addr] = ' ';
-// buffer.charAttributes[buffer.windowBase + l][c + addr] = 0;
-// continue;
-// }
-// addr++;
-// }
-
- while(c + addr < buffer.width && buffer.charAttributes[buffer.windowBase + l][c + addr] == currAttr) {
- addr++;
- }
-
- // Clear the background in preparation for writing text.
- paint.setColor(bg);
- canvas.drawRect(c * charWidth + xoffset, l * charHeight + yoffset,
- (c + addr) * charWidth + xoffset, (l+1) * charHeight + yoffset, paint);
- paint.setColor(fg);
-
- // Check for the underline attribute and set the brush accordingly.
- paint.setUnderlineText((currAttr & VDUBuffer.UNDERLINE) != 0);
-
- // Write the text string starting at 'c' for 'addr' number of characters.
- if ((currAttr & VDUBuffer.INVISIBLE) == 0)
- canvas.drawText(buffer.charArray[buffer.windowBase + l],
- c, addr,
- c * charWidth + xoffset,
- (l + 1) * charHeight - charDescent + yoffset,
- paint);
-
- // Advance to the next text block with different characteristics.
- c += addr - 1;
- }
- }
-
- buffer.update[0] = false;
-
- time = System.currentTimeMillis() - time;
- Log.d("redraw", "redraw called and updated lines=" + lines + " taking ms=" + time);
-
- postInvalidate();
- }
-
- public void updateScrollBar() {
- // TODO Auto-generated method stub
- }
-
- public void start(InputStream in, OutputStream out) {
- this.in = in;
- this.out = out;
-
- reader = new Thread(this);
- reader.start();
- }
-
- public VDUBuffer getVDUBuffer() {
- return buffer;
- }
-
- public void setVDUBuffer(VDUBuffer buffer) {
- this.buffer = buffer;
- buffer.setDisplay(this);
- }
-
- public void run() {
- byte[] b = new byte[256];
- int n = 0;
- while (n >= 0)
- try {
- n = in.read(b);
- if (n > 0) emulation.putString(new String(b, 0, n, encoding));
- redraw();
- } catch (IOException e) {
- reader = null;
- break;
- }
- }
-}
diff --git a/src/org/theb/ssh/PasswordDialog.java b/src/org/theb/ssh/PasswordDialog.java
deleted file mode 100644
index 4bbe89e..0000000
--- a/src/org/theb/ssh/PasswordDialog.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import org.connectbot.R;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-
-public class PasswordDialog extends Activity implements OnClickListener {
- private EditText mPassword;
- private Button mOK;
-
- @Override
- public void onCreate(Bundle savedValues) {
- super.onCreate(savedValues);
-
- setContentView(R.layout.password_dialog);
-
- mPassword = (EditText) findViewById(R.id.password);
- mOK = (Button) findViewById(R.id.ok);
- mOK.setOnClickListener(this);
- }
-
- public void onClick(View arg0) {
- Intent intent = this.getIntent();
- intent.putExtra(Intent.EXTRA_TEXT, mPassword.getText().toString());
- setResult(RESULT_OK, intent);
- finish();
- }
-}
diff --git a/src/org/theb/ssh/Pubkey.java b/src/org/theb/ssh/Pubkey.java
deleted file mode 100644
index a8ccb7b..0000000
--- a/src/org/theb/ssh/Pubkey.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.util.concurrent.Semaphore;
-
-import org.connectbot.R;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-
-public class Pubkey extends Activity {
- private static SecureRandom mSecRand = null;
- //private static KeyStore mKeyStore = null;
- private Thread kgThread = null;
-
- private static final int GATHER_ENTROPY = 0;
-
- protected Semaphore entropyGathered;
- protected String entropySeed;
-
- protected Button generateButton;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- setContentView(R.layout.pubkey);
-
- generateButton = (Button) findViewById(R.id.generate);
- generateButton.setOnClickListener(mGenerateListener);
-
- Button okButton = (Button) findViewById(R.id.ok);
- okButton.setOnClickListener(mCommitListener);
-
- Button cancelButton = (Button) findViewById(R.id.cancel);
- cancelButton.setOnClickListener(mCancelListener);
- }
-
- final Runnable mKeyGen = new Runnable() {
- public void run() {
- // TODO Auto-generated method stub
-// Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
- try {
- mSecRand = SecureRandom.getInstance("SHA1PRNG");
-
- entropyGathered = new Semaphore(0);
- gatherEntropy();
- entropyGathered.acquire();
- mSecRand.setSeed(entropySeed.getBytes());
- entropyGathered = null;
-
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
- keyGen.initialize(512, mSecRand);
-
- KeyPair pair = keyGen.generateKeyPair();
- PrivateKey priv = pair.getPrivate();
- PublicKey pub = pair.getPublic();
-
- byte[] encPriv = priv.getEncoded();
- byte[] encPub = pub.getEncoded();
- Log.e("SSH/priv", new String(encPriv));
- Log.d("SSH/pub", new String(encPub));
- } catch (Exception ex) {
- Log.e("SSH/keygen", ex.getMessage());
- }
- }
- };
-
- OnClickListener mGenerateListener = new OnClickListener() {
- public void onClick(View v) {
- kgThread = new Thread(mKeyGen);
- kgThread.start();
- }
- };
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == GATHER_ENTROPY) {
- entropySeed = data.getStringExtra(Intent.EXTRA_TEXT);
- entropyGathered.release();
- }
- }
-
- protected void gatherEntropy() {
- generateButton.setEnabled(false);
- Intent intent = new Intent(this, TouchEntropy.class);
- this.startActivityForResult(intent, GATHER_ENTROPY);
- }
-
- OnClickListener mCommitListener = new OnClickListener() {
- public void onClick(View v) {
- // When the user clicks, just finish this activity.
- // onPause will be called, and we save our data there.
- finish();
- }
- };
-
- OnClickListener mCancelListener = new OnClickListener() {
- public void onClick(View v) {
- //cancelEdit();
- finish();
- }
- };
-}
diff --git a/src/org/theb/ssh/SecureShell.java b/src/org/theb/ssh/SecureShell.java
deleted file mode 100644
index 32a8b10..0000000
--- a/src/org/theb/ssh/SecureShell.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.connectbot.R;
-import org.theb.provider.HostDb;
-
-import com.trilead.ssh2.ConnectionMonitor;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.Intent;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.KeyCharacterMap;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.Window;
-
-public class SecureShell extends Activity implements FeedbackUI, ConnectionMonitor {
- private ConnectionThread mConn;
-
- // Activities we support.
- static final int PASSWORD_REQUEST = 0;
-
- // Database projection indices.
- private static final int HOSTNAME_INDEX = 1;
- private static final int USERNAME_INDEX = 2;
- private static final int PORT_INDEX = 3;
-
- private static final String[] PROJECTION = new String[] {
- HostDb.Hosts._ID, // 0
- HostDb.Hosts.HOSTNAME, // 1
- HostDb.Hosts.USERNAME, // 2
- HostDb.Hosts.PORT, // 3
- };
-
- private Cursor mCursor;
-
- // Map to convert from keyboard presses to actual characters.
- private KeyCharacterMap mKMap;
-
- // Terminal window
- private Terminal mTerminal;
-
- // We change the meta state when the user presses the center button.
- private boolean mMetaState = false;
-
- // Store the username, hostname, and port from the database.
- private String mHostname;
- private String mUsername;
- private int mPort;
-
- // The toggle for the original thread to release the indeterminate waiting graphic.
- private ProgressDialog progress;
- private boolean mIsWaiting;
- private String mWaitingTitle;
- private String mWaitingMessage;
-
- final Handler mHandler = new Handler();
-
- // Tell the user why we disconnected.
- private String mDisconnectReason;
-
- @Override
- public void onCreate(Bundle savedValues) {
- super.onCreate(savedValues);
-
- // TODO: enable opengl for testing on real devices
- //requestWindowFeature(Window.FEATURE_OPENGL);
- requestWindowFeature(Window.FEATURE_PROGRESS);
- mTerminal = new JTATerminalView(this);
-
- // TODO: implement scroll bar on right.
- setContentView((View)mTerminal);
-
- Log.d("SSH", "using URI " + getIntent().getData().toString());
-
-// mCursor = managedQuery(getIntent().getData(), PROJECTION, null, null);
- mCursor.moveToFirst();
-
- mHostname = mCursor.getString(HOSTNAME_INDEX);
- mUsername = mCursor.getString(USERNAME_INDEX);
- mPort = mCursor.getInt(PORT_INDEX);
-
- String title = "SSH: " + mUsername + "@" + mHostname;
- if (mPort != 22)
- title += Integer.toString(mPort);
-
- this.setTitle(title);
-
- mConn = new TrileadConnectionThread(this, mTerminal, mHostname, mUsername, mPort);
-
- mKMap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
-
- Log.d("SSH", "Starting new ConnectionThread");
- mConn.start();
- }
-
- public void setWaiting(boolean isWaiting, String title, String message) {
- mIsWaiting = isWaiting;
- mWaitingTitle = title;
- mWaitingMessage = message;
- mHandler.post(mUpdateWaiting);
- }
-
- final Runnable mUpdateWaiting = new Runnable() {
- public void run() {
- if (mIsWaiting) {
- if (progress == null)
- progress = ProgressDialog.show(SecureShell.this, mWaitingTitle, mWaitingMessage, true, false);
- else {
- progress.setTitle(mWaitingTitle);
- progress.setMessage(mWaitingMessage);
- }
- } else {
- if (progress != null) {
- progress.dismiss();
- progress = null;
- }
- }
- }
- };
-
- public void askPassword() {
- Intent intent = new Intent(this, PasswordDialog.class);
- this.startActivityForResult(intent, PASSWORD_REQUEST);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == PASSWORD_REQUEST) {
- mConn.setPassword(data.getStringExtra(Intent.EXTRA_TEXT));
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- mConn.finish();
- mConn = null;
-
- finish();
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent msg) {
- final OutputStream out = mConn.getWriter();
- if (out != null) {
- try {
- if (mKMap.isPrintingKey(keyCode)
- || keyCode == KeyEvent.KEYCODE_SPACE) {
- int c = mKMap.get(keyCode, msg.getMetaState());
- if (mMetaState) {
- // Support CTRL-A through CTRL-Z
- if (c >= 0x61 && c <= 0x79)
- c -= 0x60;
- else if (c >= 0x40 && c <= 0x59)
- c -= 0x39;
- mMetaState = false;
- }
- out.write(c);
- } else if (keyCode == KeyEvent.KEYCODE_DEL) {
- out.write(0x08); // CTRL-H
- } else if (keyCode == KeyEvent.KEYCODE_ENTER
- || keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- || keyCode == KeyEvent.KEYCODE_DPAD_UP
- || keyCode == KeyEvent.KEYCODE_DPAD_DOWN
- || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- byte[] output = mTerminal.getKeyCode(keyCode, msg.getMetaState());
- if (output != null)
- out.write(output);
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- if (mMetaState) {
- out.write(0x1B); // ESCAPE
- mMetaState = false;
- } else {
- mMetaState = true;
- }
- } else {
- // This is not something we handle.
- return super.onKeyDown(keyCode, msg);
- }
- return true;
- } catch (IOException e) {
- Log.e("SSH", "Can't write to stdout: "+ e.getMessage());
- }
- }
- return super.onKeyDown(keyCode, msg);
- }
-
- final Runnable mDisconnectAlert = new Runnable() {
- public void run() {
- if (SecureShell.this.isFinishing())
- return;
-
-// AlertDialog d = AlertDialog.show(SecureShell.this,
-// "Connection Lost", mDisconnectReason, "Ok", false);
- new AlertDialog.Builder(SecureShell.this)
- .setIcon(R.drawable.icon)
- .setTitle(R.string.alert_disconnect_msg)
- .setPositiveButton(R.string.button_ok, null)
- .show();
- // TODO: Return to previous activity if connection fails.
- }
- };
-
- public void connectionLost(Throwable reason) {
- Log.d("SSH", "Connection ended.");
- mDisconnectReason = reason.getMessage();
- mHandler.post(mDisconnectAlert);
- }
-}
diff --git a/src/org/theb/ssh/Terminal.java b/src/org/theb/ssh/Terminal.java
deleted file mode 100644
index 890f6b0..0000000
--- a/src/org/theb/ssh/Terminal.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public interface Terminal {
-
- public int getWidth();
- public int getHeight();
- public int getRowCount();
- public int getColumnCount();
- public void start(InputStream in, OutputStream out);
- public byte[] getKeyCode(int keyCode, int meta);
-}
diff --git a/src/org/theb/ssh/TouchEntropy.java b/src/org/theb/ssh/TouchEntropy.java
deleted file mode 100644
index 772585e..0000000
--- a/src/org/theb/ssh/TouchEntropy.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.theb.ssh;
-
-import org.connectbot.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.graphics.Paint.FontMetrics;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-
-public class TouchEntropy extends Activity {
- protected String mEntropy;
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- mEntropy = new String();
- setContentView(new TouchView(this));
- }
-
- class TouchView extends View {
- Paint mPaint;
- FontMetrics mFontMetrics;
-
- private boolean mFlipFlop = false;
- private long mLastTime = 0;
-
- public TouchView(Context c) {
- super(c);
-
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setTypeface(Typeface.DEFAULT);
- mPaint.setTextAlign(Paint.Align.CENTER);
- mPaint.setTextSize(16);
- mPaint.setColor(Color.WHITE);
- mFontMetrics = mPaint.getFontMetrics();
- }
-
- @Override
- public void onDraw(Canvas c) {
- String prompt = getResources().getString(R.string.prompt_touch);
- c.drawText(prompt + " " + (int)(100.0 * (mEntropy.length() / 20.0)) + "% done",
- getWidth() / 2,
- getHeight() / 2 - (mFontMetrics.ascent + mFontMetrics.descent) / 2,
- mPaint);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // Only get entropy every 200 milliseconds to ensure the user has moved around.
- long now = System.currentTimeMillis();
- if ((now - mLastTime) < 200)
- return true;
- else
- mLastTime = now;
-
- Log.d("SSH", "Last time was " + mLastTime);
-
-
- // Get the lowest 4 bits of each X, Y input and concat to the entropy-gathering
- // string.
- if (mFlipFlop)
- mEntropy += (byte)(((int)event.getX() & 0xF0) | ((int)event.getY() & 0x0F));
- else
- mEntropy += (byte)(((int)event.getY() & 0xF0) | ((int)event.getX() & 0x0F));
-
- mFlipFlop = !mFlipFlop;
-
- // SHA1PRNG only keeps 20 bytes (160 bits) of entropy.
- if (mEntropy.length() > 20) {
- Intent intent = TouchEntropy.this.getIntent();
- intent.putExtra(Intent.EXTRA_TEXT, mEntropy);
- TouchEntropy.this.setResult(RESULT_OK, intent);
- TouchEntropy.this.finish();
- }
-
- invalidate();
-
- return true;
- }
- }
-}
diff --git a/src/org/theb/ssh/TrileadConnectionThread.java b/src/org/theb/ssh/TrileadConnectionThread.java
deleted file mode 100644
index b874756..0000000
--- a/src/org/theb/ssh/TrileadConnectionThread.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2007 Kenny Root (kenny at the-b.org)
- *
- * This file is part of Connectbot.
- *
- * Connectbot is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Connectbot is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Connectbot. If not, see <http://www.gnu.org/licenses/>.
- */
-package org.theb.ssh;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.concurrent.Semaphore;
-
-import com.trilead.ssh2.Connection;
-import com.trilead.ssh2.ConnectionMonitor;
-import com.trilead.ssh2.Session;
-
-public class TrileadConnectionThread extends ConnectionThread {
- private String hostname;
- private String username;
- private String password;
- private int port;
-
- private Connection connection;
- private Session session;
-
- private InputStream stdOut;
- private OutputStream stdIn;
-
- private Semaphore sPass;
-
- //protected FeedbackUI ui;
- protected Terminal term;
-
- public TrileadConnectionThread(FeedbackUI ui, Terminal term, String hostname, String username, int port) {
- super(ui, hostname, username, port);
- //this.ui = ui;
- this.term = term;
- this.hostname = hostname;
- this.username = username;
- this.port = port;
- }
-
- @Override
- public void finish() {
- if (session != null) {
- session.close();
- session = null;
- }
-
- if (connection != null) {
- connection.close();
- connection = null;
- }
- }
-
- @Override
- public InputStream getReader() {
- return stdOut;
- }
-
- @Override
- public OutputStream getWriter() {
- return stdIn;
- }
-
- @Override
- public void run() {
- connection = new Connection(hostname, port);
-
- //connection.addConnectionMonitor((ConnectionMonitor) ui);
- //ui.setWaiting(true, "Connection", "Connecting to " + hostname + "...");
-
- try {
- connection.connect(new InteractiveHostKeyVerifier());
-
- //ui.setWaiting(true, "Authenticating", "Trying to authenticate...");
-
- // boolean enableKeyboardInteractive = true;
- // boolean enableDSA = true;
- // boolean enableRSA = true;
-
- while (true) {
- /*
- * if ((enableDSA || enableRSA ) &&
- * mConn.isAuthMethodAvailable(username, "publickey");
- */
-
- if (connection.isAuthMethodAvailable(username, "password")) {
- //ui.setWaiting(true, "Authenticating","Trying to authenticate using password...");
-
- // Set a semaphore that is unset by the returning dialog.
-// sPass = new Semaphore(0);
-// ui.askPassword();
-//
-// // Wait for the user to answer.
-// sPass.acquire();
-// sPass = null;
-// if (password == null)
-// continue;
-
- password = "b0tt";
-
- boolean res = connection.authenticateWithPassword(username, password);
- password = null;
- if (res == true)
- break;
-
- continue;
- }
-
- throw new IOException(
- "No supported authentication methods available.");
- }
-
- //ui.setWaiting(true, "Session", "Requesting shell...");
-
- session = connection.openSession();
-
- session.requestPTY("xterm", // BUGFIX: allow colors with xterm instead of vt100
- term.getColumnCount(), term.getRowCount(),
- term.getWidth(), term.getHeight(),
- null);
-
- session.startShell();
-
- stdIn = session.getStdin();
- // stderr = session.getStderr();
- stdOut = session.getStdout();
-
- //ui.setWaiting(false, null, null);
- } catch (IOException e) {
- //ui.setWaiting(false, null, null);
- return;
- }
-
- term.start(stdOut, stdIn);
- }
-
- @Override
- public void setPassword(String password) {
- if (password == null)
- this.password = "";
- else
- this.password = password;
- sPass.release();
- }
-}