diff options
Diffstat (limited to 'src')
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(); - } -} |