diff options
author | Jeffrey Sharkey <jsharkey@jsharkey.org> | 2008-09-11 21:55:38 +0000 |
---|---|---|
committer | Jeffrey Sharkey <jsharkey@jsharkey.org> | 2008-09-11 21:55:38 +0000 |
commit | 071e39dc7e7d06c021a6d65ae7a65242c8ea99ed (patch) | |
tree | 71ac1b00fa9fc45cf155021879ab55f1ff395611 /src | |
parent | 6681b4c809bf76cd558c5b314b6de9cfc98bc187 (diff) | |
download | connectbot-071e39dc7e7d06c021a6d65ae7a65242c8ea99ed.tar.gz connectbot-071e39dc7e7d06c021a6d65ae7a65242c8ea99ed.tar.bz2 connectbot-071e39dc7e7d06c021a6d65ae7a65242c8ea99ed.zip |
* WARNING: this build is broken lol
* moving more stuff over to new frontend gui in org.connectbot
* found out that we dont need a contentprovider to make desktop shortcuts, will be easy to add ssh://user@host/ uri shortcut handling
* new host-editing backend that uses preferences hack, will blog about this technique later today
* using colors to categorize hosts (does this work?)
* moved host-specific options (like disconnect/edit/delete) to long-tap menu instead of main menu
Diffstat (limited to 'src')
-rw-r--r-- | src/com/trilead/ssh2/channel/ChannelManager.java | 3 | ||||
-rw-r--r-- | src/org/connectbot/Console.java | 1 | ||||
-rw-r--r-- | src/org/connectbot/HostEditor.java | 208 | ||||
-rw-r--r-- | src/org/connectbot/HostList.java | 259 | ||||
-rw-r--r-- | src/org/connectbot/R.java | 113 | ||||
-rw-r--r-- | src/org/connectbot/util/HostAdapter.java | 128 | ||||
-rw-r--r-- | src/org/connectbot/util/HostDatabase.java | 101 | ||||
-rw-r--r-- | src/org/theb/ssh/HostEditor.java | 2 | ||||
-rw-r--r-- | src/org/theb/ssh/HostsList.java | 2 | ||||
-rw-r--r-- | src/org/theb/ssh/PasswordDialog.java | 2 | ||||
-rw-r--r-- | src/org/theb/ssh/Pubkey.java | 2 | ||||
-rw-r--r-- | src/org/theb/ssh/SecureShell.java | 2 | ||||
-rw-r--r-- | src/org/theb/ssh/TouchEntropy.java | 2 |
13 files changed, 812 insertions, 13 deletions
diff --git a/src/com/trilead/ssh2/channel/ChannelManager.java b/src/com/trilead/ssh2/channel/ChannelManager.java index 74906d3..e582a52 100644 --- a/src/com/trilead/ssh2/channel/ChannelManager.java +++ b/src/com/trilead/ssh2/channel/ChannelManager.java @@ -698,7 +698,8 @@ public class ChannelManager implements MessageHandler }
try {
- waitForChannelSuccessOrFailure(c);
+ //waitForChannelSuccessOrFailure(c);
+ this.waitForChannelRequestResult(c);
} catch (IOException e) {
throw (IOException) new IOException("PTY request failed")
.initCause(e);
diff --git a/src/org/connectbot/Console.java b/src/org/connectbot/Console.java index 2895ed5..4493ac7 100644 --- a/src/org/connectbot/Console.java +++ b/src/org/connectbot/Console.java @@ -5,7 +5,6 @@ import org.connectbot.service.TerminalBridgeSurface; import org.connectbot.service.TerminalManager; import org.theb.ssh.InteractiveHostKeyVerifier; -import org.theb.ssh.R; import com.trilead.ssh2.Connection; import de.mud.terminal.vt320; diff --git a/src/org/connectbot/HostEditor.java b/src/org/connectbot/HostEditor.java index 373897d..97ddc14 100644 --- a/src/org/connectbot/HostEditor.java +++ b/src/org/connectbot/HostEditor.java @@ -1,15 +1,213 @@ package org.connectbot; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.connectbot.util.HostDatabase; + + + import android.app.Activity; +import android.content.ContentValues; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; -import org.theb.ssh.R; +import android.preference.CheckBoxPreference; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.util.Log; + +public class HostEditor extends PreferenceActivity implements OnSharedPreferenceChangeListener { + + + public class CursorPreferenceHack implements SharedPreferences { + + protected final SQLiteDatabase db; + protected final String table; + protected final int id; + + protected Map<String, String> values = new HashMap<String, String>(); + + public CursorPreferenceHack(SQLiteDatabase db, String table, int id) { + this.db = db; + this.table = table; + this.id = id; + + this.cacheValues(); + + } + + protected void cacheValues() { + // fill a cursor and cache the values locally + // this makes sure we dont have any floating cursor to dispose later + + Cursor cursor = db.query(table, null, "_id = ?", + new String[] { Integer.toString(id) }, null, null, null); + cursor.moveToFirst(); + + for(int i = 0; i < cursor.getColumnCount(); i++) { + String key = cursor.getColumnName(i); + String value = cursor.getString(i); + values.put(key, value); + } + + cursor.close(); + + } + + public boolean contains(String key) { + return values.containsKey(key); + } + + public class Editor implements SharedPreferences.Editor { + + public ContentValues update = new ContentValues(); + + public SharedPreferences.Editor clear() { + Log.d(this.getClass().toString(), "clear()"); + update = new ContentValues(); + return this; + } + + public boolean commit() { + Log.d(this.getClass().toString(), "commit() changes back to database"); + db.update(table, update, "_id = ?", new String[] { Integer.toString(id) }); + + // make sure we refresh the parent cached values + cacheValues(); + + // and update any listeners + for(OnSharedPreferenceChangeListener listener : listeners) { + listener.onSharedPreferenceChanged(CursorPreferenceHack.this, null); + } + + return true; + } + + public android.content.SharedPreferences.Editor putBoolean(String key, boolean value) { + return this.putString(key, Boolean.toString(value)); + } + + public android.content.SharedPreferences.Editor putFloat(String key, float value) { + return this.putString(key, Float.toString(value)); + } + + public android.content.SharedPreferences.Editor putInt(String key, int value) { + return this.putString(key, Integer.toString(value)); + } + + public android.content.SharedPreferences.Editor putLong(String key, long value) { + return this.putString(key, Long.toString(value)); + } + + public android.content.SharedPreferences.Editor putString(String key, String value) { + Log.d(this.getClass().toString(), String.format("Editor.putString(key=%s, value=%s)", key, value)); + update.put(key, value); + return this; + } + + public android.content.SharedPreferences.Editor remove(String key) { + Log.d(this.getClass().toString(), String.format("Editor.remove(key=%s)", key)); + update.remove(key); + return this; + } + + } + -public class HostEditor extends Activity { + public Editor edit() { + Log.d(this.getClass().toString(), "edit()"); + return new Editor(); + } + + public Map<String, ?> getAll() { + return values; + } + + public boolean getBoolean(String key, boolean defValue) { + return Boolean.valueOf(this.getString(key, Boolean.toString(defValue))); + } + + public float getFloat(String key, float defValue) { + return Float.valueOf(this.getString(key, Float.toString(defValue))); + } + + public int getInt(String key, int defValue) { + return Integer.valueOf(this.getString(key, Integer.toString(defValue))); + } + + public long getLong(String key, long defValue) { + return Long.valueOf(this.getString(key, Long.toString(defValue))); + } + + public String getString(String key, String defValue) { + Log.d(this.getClass().toString(), String.format("getString(key=%s, defValue=%s)", key, defValue)); + + if(!values.containsKey(key)) return defValue; + return values.get(key); + } + + public List<OnSharedPreferenceChangeListener> listeners = new LinkedList<OnSharedPreferenceChangeListener>(); + + public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { + listeners.add(listener); + } + + public void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { + listeners.remove(listener); + } + + } + + + @Override + public SharedPreferences getSharedPreferences(String name, int mode) { + Log.d(this.getClass().toString(), String.format("getSharedPreferences(name=%s)", name)); + return this.pref; + } + + public CursorPreferenceHack pref; @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setContentView(R.layout.act_hosteditor); + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + HostDatabase db = new HostDatabase(this); + int id = this.getIntent().getIntExtra(Intent.EXTRA_TITLE, -1); + + // TODO: we could pass through a specific ContentProvider uri here + //this.getPreferenceManager().setSharedPreferencesName(uri); + + this.pref = new CursorPreferenceHack(db.getWritableDatabase(), db.TABLE_HOSTS, id); + this.pref.registerOnSharedPreferenceChangeListener(this); + + this.addPreferencesFromResource(R.xml.host_prefs); + + this.updateSummaries(); + + + } + + public void updateSummaries() { + // for all text preferences, set hint as current database value + for(String key : this.pref.values.keySet()) { + Preference pref = this.findPreference(key); + if(pref == null) continue; + if(pref instanceof CheckBoxPreference) continue; + pref.setSummary(this.pref.getString(key, "")); + } + + } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + // update values on changed preference + this.updateSummaries(); + } } diff --git a/src/org/connectbot/HostList.java b/src/org/connectbot/HostList.java new file mode 100644 index 0000000..3689fbc --- /dev/null +++ b/src/org/connectbot/HostList.java @@ -0,0 +1,259 @@ +package org.connectbot; + +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.HostDatabase; +import org.theb.ssh.InteractiveHostKeyVerifier; + +import com.trilead.ssh2.Connection; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.ServiceConnection; +import android.database.Cursor; +import android.os.Bundle; +import android.os.IBinder; +import android.view.ContextMenu; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.MenuItem.OnMenuItemClickListener; +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 HostList 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 HostDatabase hostdb; + public Cursor hosts; + public ListView list; + public HostAdapter adapter; + + public int COL_ID, COL_NICKNAME, COL_USERNAME, COL_HOSTNAME, COL_CONNECTED; + + @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); + + // connect with hosts database and populate list + this.hostdb = new HostDatabase(this); + this.list = (ListView) this.findViewById(R.id.front_hostlist); + this.updateCursor(); + + //this.list.setSelector(R.drawable.highlight_disabled_pressed); + + this.COL_ID = hosts.getColumnIndexOrThrow("_id"); + this.COL_NICKNAME = hosts.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_NICKNAME); + this.COL_USERNAME = hosts.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_USERNAME); + this.COL_HOSTNAME = hosts.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_HOSTNAME); + this.COL_CONNECTED = hosts.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_LASTCONNECT); + + this.list.setOnItemClickListener(new OnItemClickListener() { + + public void onItemClick(AdapterView<?> parent, View view, + int position, long id) { + + // launch off to console details + // TODO: package information about connection selected + HostList.this.startActivity(new Intent(HostList.this, + Console.class)); + + } + + }); + + this.registerForContextMenu(this.list); + + final Pattern hostmask = Pattern.compile(".+@.+(:\\d+)?"); + final TextView text = (TextView) this + .findViewById(R.id.front_quickconnect); + text.setOnKeyListener(new OnKeyListener() { + + public boolean onKey(View v, int keyCode, KeyEvent event) { + + // make sure we follow pattern + if (text.getText().length() < 1) + return false; + + // TODO: only show error when trying to hit enter + if (!hostmask.matcher(text.getText().toString()).find()) { + text.setError("Use the format 'username@hostname:port'"); + } + + // 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; + } + + }); + + } + + public MenuItem sortcolor, sortlast; + public boolean sortedByColor = false; + + public void updateCursor() { + + // refresh cursor because of possible sorting change + if(this.hosts != null) + this.hosts.close(); + this.hosts = this.hostdb.allHosts(sortedByColor); + this.adapter = new HostAdapter(this, this.hosts); + this.list.setAdapter(adapter); + + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + + sortcolor.setVisible(!sortedByColor); + sortlast.setVisible(sortedByColor); + + return true; + + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + // add host, ssh keys, about + + MenuItem add = menu.add(0, 0, Menu.NONE, "New host"); + add.setIcon(android.R.drawable.ic_menu_add); + add.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + return false; + } + }); + + sortcolor = menu.add(0, 0, Menu.NONE, "Sort by color"); + sortcolor.setIcon(android.R.drawable.ic_menu_share); + sortcolor.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + sortedByColor = true; + updateCursor(); + return false; + } + }); + + sortlast = menu.add(0, 0, Menu.NONE, "Sort by last"); + sortlast.setIcon(android.R.drawable.ic_menu_share); + sortlast.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + sortedByColor = false; + updateCursor(); + return false; + } + }); + + MenuItem keys = menu.add(0, 0, Menu.NONE, "Manage keys"); + keys.setIcon(android.R.drawable.ic_lock_lock); + + MenuItem settings = menu.add(0, 0, Menu.NONE, "Settings"); + settings.setIcon(android.R.drawable.ic_menu_preferences); + + MenuItem about = menu.add(0, 0, Menu.NONE, "About"); + about.setIcon(android.R.drawable.ic_menu_help); + + return true; + + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenu.ContextMenuInfo menuInfo) { + + // create menu to handle hosts + + // create menu to handle deleting and sharing lists + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; + Cursor cursor = (Cursor) this.list.getItemAtPosition(info.position); + + menu.setHeaderTitle(cursor.getString(COL_NICKNAME)); + final int id = cursor.getInt(COL_ID); + + // edit, disconnect, delete + // TODO: change disconnect/connect based on status + MenuItem connect = menu.add(0, 0, Menu.NONE, "Disconnect"); + connect.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + return false; + } + }); + + MenuItem edit = menu.add(0, 0, Menu.NONE, "Edit host"); + edit.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + Intent intent = new Intent(HostList.this, HostEditor.class); + intent.putExtra(Intent.EXTRA_TITLE, id); + HostList.this.startActivity(intent); + return false; + } + }); + + MenuItem delete = menu.add(0, 0, Menu.NONE, "Delete host"); + delete.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + return false; + } + }); + + } + +} diff --git a/src/org/connectbot/R.java b/src/org/connectbot/R.java new file mode 100644 index 0000000..b1a337f --- /dev/null +++ b/src/org/connectbot/R.java @@ -0,0 +1,113 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package org.connectbot; + +public final class R { + public static final class anim { + public static final int fade_out=0x7f040000; + public static final int fade_stay_hidden=0x7f040001; + public static final int slide_left_in=0x7f040002; + public static final int slide_left_out=0x7f040003; + public static final int slide_right_in=0x7f040004; + public static final int slide_right_out=0x7f040005; + } + public static final class array { + public static final int list_colors=0x7f060001; + public static final int list_emulation_modes=0x7f060000; + } + public static final class attr { + } + public static final class color { + public static final int blue=0x7f080000; + public static final int green=0x7f080001; + public static final int red=0x7f080002; + } + public static final class drawable { + public static final int blue=0x7f020002; + public static final int even_stripe=0x7f020003; + public static final int highlight_disabled_pressed=0x7f020000; + public static final int icon=0x7f020001; + public static final int odd_stripe=0x7f020004; + } + public static final class id { + public static final int add=0x7f090011; + public static final int cancel=0x7f090012; + public static final int console_flip=0x7f090002; + public static final int copyright=0x7f090001; + public static final int dismiss=0x7f090019; + 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=0x7f09001d; + public static final int host_caption=0x7f090015; + public static final int host_connected=0x7f090013; + public static final int host_title=0x7f090014; + public static final int hostname=0x7f09000e; + public static final int hostnameLabel=0x7f09000d; + public static final int icon=0x7f090000; + public static final int keyName=0x7f09001e; + public static final int message=0x7f090018; + public static final int ok=0x7f09001c; + public static final int password=0x7f09001b; + public static final int passwordLabel=0x7f09001a; + public static final int port=0x7f090010; + public static final int portLabel=0x7f09000f; + public static final int shell=0x7f090017; + public static final int terminal=0x7f09001f; + public static final int terminal_overlay=0x7f090016; + public static final int username=0x7f09000c; + public static final int usernameLabel=0x7f09000b; + } + public static final class layout { + public static final int about_dialog=0x7f030000; + public static final int act_console=0x7f030001; + public static final int act_frontpage=0x7f030002; + public static final int act_hosteditor=0x7f030003; + public static final int host_editor=0x7f030004; + public static final int item_host=0x7f030005; + public static final int item_terminal=0x7f030006; + public static final int main=0x7f030007; + public static final int message_dialog=0x7f030008; + public static final int password_dialog=0x7f030009; + public static final int pubkey=0x7f03000a; + public static final int secure_shell=0x7f03000b; + } + public static final class string { + public static final int alert_disconnect_msg=0x7f070014; + public static final int app_name=0x7f070000; + public static final int button_add=0x7f070010; + public static final int button_cancel=0x7f070011; + public static final int button_change=0x7f070012; + public static final int button_generate=0x7f070013; + public static final int button_ok=0x7f07000f; + public static final int menu_about=0x7f07000d; + public static final int menu_delete=0x7f07000a; + public static final int menu_insert=0x7f070009; + public static final int menu_preferences=0x7f07000b; + public static final int menu_pubkey=0x7f07000c; + public static final int msg_copyright=0x7f070015; + public static final int msg_version=0x7f070016; + public static final int prompt_touch=0x7f07000e; + public static final int resolve_connect=0x7f070008; + public static final int resolve_edit=0x7f070007; + public static final int title_entropy=0x7f070006; + public static final int title_host=0x7f070002; + public static final int title_hosts_list=0x7f070001; + public static final int title_password=0x7f070004; + public static final int title_pubkey=0x7f070005; + public static final int title_shell=0x7f070003; + } + public static final class xml { + public static final int host_prefs=0x7f050000; + } +} diff --git a/src/org/connectbot/util/HostAdapter.java b/src/org/connectbot/util/HostAdapter.java new file mode 100644 index 0000000..3dec83c --- /dev/null +++ b/src/org/connectbot/util/HostAdapter.java @@ -0,0 +1,128 @@ +package org.connectbot.util; + + +import org.connectbot.R; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + + +public class HostAdapter extends BaseAdapter { + + + public final Context context; + public final LayoutInflater inflater; + public final Cursor source; + + public final static String TABLE_HOSTS = "hosts"; + public final static String FIELD_HOST_NICKNAME = "nickname"; + public final static String FIELD_HOST_USERNAME = "username"; + public final static String FIELD_HOST_HOSTNAME = "hostname"; + public final static String FIELD_HOST_PORT = "port"; + public final static String FIELD_HOST_HOSTKEY = "hostkey"; + public final static String FIELD_HOST_CONNECTED = "connected"; + + public final int COL_ID, COL_NICKNAME, COL_USERNAME, COL_HOSTNAME, COL_CONNECTED, COL_COLOR; + + public final ColorStateList red, green, blue; + + public HostAdapter(Context context, Cursor source) { + this.context = context; + this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + this.source = source; + + this.COL_ID = source.getColumnIndexOrThrow("_id"); + this.COL_NICKNAME = source.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_NICKNAME); + this.COL_USERNAME = source.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_USERNAME); + this.COL_HOSTNAME = source.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_HOSTNAME); + this.COL_CONNECTED = source.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_LASTCONNECT); + this.COL_COLOR = source.getColumnIndexOrThrow(HostDatabase.FIELD_HOST_COLOR); + + Resources res = this.context.getResources(); + this.red = res.getColorStateList(R.color.red); + this.green = res.getColorStateList(R.color.green); + this.blue = res.getColorStateList(R.color.blue); + + } + + public Object getItem(int position) { + source.moveToPosition(position); + return source; + } + + public boolean hasStableIds() { + return true; + } + + public int getCount() { + return source.getCount(); + } + + public long getItemId(int position) { + return position; + } + + protected ColorStateList resolve(String color) { + if(HostDatabase.COLOR_RED.equals(color)) return this.red; + if(HostDatabase.COLOR_GREEN.equals(color)) return this.green; + if(HostDatabase.COLOR_BLUE.equals(color)) return this.blue; + return null; + } + + public synchronized View getView(int position, View convertView, ViewGroup parent) { + + this.source.moveToPosition(position); + + if(convertView == null) { + convertView = this.inflater.inflate(R.layout.item_host, parent, false); + } + + String nice = "never"; + int minutes = ((int)(System.currentTimeMillis() / 1000) - source.getInt(COL_CONNECTED)) / 60; + if(minutes > 0) { + nice = String.format("%d minutes ago", minutes); + if(minutes >= 60) { + int hours = minutes / 60; + nice = String.format("%d hours ago", hours); + if(hours >= 24) { + int days = hours / 24; + nice = String.format("%d days ago", days); + } + } + } + + boolean connected = true; + + TextView title = (TextView)convertView.findViewById(R.id.host_title); + title.setText(source.getString(COL_NICKNAME)); + + TextView caption = (TextView)convertView.findViewById(R.id.host_caption); + caption.setText(String.format("%s%s", nice, connected ? ", connected" : "")); + + // correctly update text color as needed + ColorStateList resolved = this.resolve(source.getString(COL_COLOR)); + if(resolved != null) { + title.setTextColor(resolved); + caption.setTextColor(resolved); + } + + ((ImageView)convertView.findViewById(R.id.host_connected)).setImageResource(connected ? android.R.drawable.presence_online : android.R.drawable.presence_offline); + + // update icon correctly if service is connected + + return convertView; + } + +}
\ No newline at end of file diff --git a/src/org/connectbot/util/HostDatabase.java b/src/org/connectbot/util/HostDatabase.java new file mode 100644 index 0000000..bbc27f9 --- /dev/null +++ b/src/org/connectbot/util/HostDatabase.java @@ -0,0 +1,101 @@ +package org.connectbot.util; + +import java.util.LinkedList; +import java.util.List; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + + +public class HostDatabase extends SQLiteOpenHelper { + + public final static String DB_NAME = "hosts"; + public final static int DB_VERSION = 4; + + public final static String TABLE_HOSTS = "hosts"; + public final static String FIELD_HOST_NICKNAME = "nickname"; + public final static String FIELD_HOST_USERNAME = "username"; + public final static String FIELD_HOST_HOSTNAME = "hostname"; + public final static String FIELD_HOST_PORT = "port"; + public final static String FIELD_HOST_HOSTKEY = "hostkey"; + public final static String FIELD_HOST_LASTCONNECT = "lastconnect"; + public final static String FIELD_HOST_COLOR = "color"; + + 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"; + + public HostDatabase(Context context) { + super(context, DB_NAME, null, DB_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + TABLE_HOSTS + + " (_id INTEGER PRIMARY KEY, " + + FIELD_HOST_NICKNAME + " TEXT, " + + FIELD_HOST_USERNAME + " TEXT, " + + FIELD_HOST_HOSTNAME + " TEXT, " + + FIELD_HOST_PORT + " INTEGER, " + + FIELD_HOST_HOSTKEY + " TEXT, " + + FIELD_HOST_LASTCONNECT + " INTEGER, " + + FIELD_HOST_COLOR + " TEXT)"); + + db.execSQL("CREATE TABLE " + TABLE_PRIVKEYS + + " (_id INTEGER PRIMARY KEY, " + + FIELD_KEY_NAME + " TEXT, " + + FIELD_KEY_PRIVATE + " TEXT)"); + + this.createHost(db, "connectbot@bravo", "connectbot", "192.168.254.230", 22, COLOR_RED); + this.createHost(db, "root@google.com", "root", "google.com", 22, COLOR_GREEN); + this.createHost(db, "cron@server.example.com", "cron", "server.example.com", 22, COLOR_BLUE); + this.createHost(db, "backup@example.net", "backup", "example.net", 22, COLOR_RED); + + } + + @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); + } + + public long createHost(SQLiteDatabase db, String nickname, String username, String hostname, int port, String color) { + // create and insert new host + + if(db == null) db = this.getWritableDatabase(); + + ContentValues values = new ContentValues(); + values.put(FIELD_HOST_NICKNAME, nickname); + values.put(FIELD_HOST_USERNAME, username); + values.put(FIELD_HOST_HOSTNAME, hostname); + values.put(FIELD_HOST_PORT, port); + values.put(FIELD_HOST_LASTCONNECT, Integer.MAX_VALUE); + if(color != null) + values.put(FIELD_HOST_COLOR, color); + + return db.insert(TABLE_HOSTS, null, values); + + } + + public Cursor allHosts(boolean sortColors) { + + String sortField = sortColors ? FIELD_HOST_COLOR : FIELD_HOST_LASTCONNECT; + + SQLiteDatabase db = this.getReadableDatabase(); + return db.query(TABLE_HOSTS, new String[] { "_id", FIELD_HOST_NICKNAME, + FIELD_HOST_USERNAME, FIELD_HOST_HOSTNAME, FIELD_HOST_PORT, + FIELD_HOST_HOSTKEY, FIELD_HOST_LASTCONNECT, FIELD_HOST_COLOR }, + null, null, null, null, sortField + " DESC"); + + } + + +} diff --git a/src/org/theb/ssh/HostEditor.java b/src/org/theb/ssh/HostEditor.java index 11bb32b..2b31ccd 100644 --- a/src/org/theb/ssh/HostEditor.java +++ b/src/org/theb/ssh/HostEditor.java @@ -18,7 +18,7 @@ */ package org.theb.ssh; -import org.theb.ssh.R; +import org.connectbot.R; import org.theb.provider.HostDb; import org.theb.provider.HostDb.Hosts; diff --git a/src/org/theb/ssh/HostsList.java b/src/org/theb/ssh/HostsList.java index 1db0f8a..5760f46 100644 --- a/src/org/theb/ssh/HostsList.java +++ b/src/org/theb/ssh/HostsList.java @@ -23,7 +23,7 @@ import java.util.concurrent.Semaphore; import org.connectbot.Console; import org.connectbot.service.TerminalBridge; import org.connectbot.service.TerminalManager; -import org.theb.ssh.R; +import org.connectbot.R; import org.theb.provider.HostDb; import com.trilead.ssh2.Connection; diff --git a/src/org/theb/ssh/PasswordDialog.java b/src/org/theb/ssh/PasswordDialog.java index adcca36..4bbe89e 100644 --- a/src/org/theb/ssh/PasswordDialog.java +++ b/src/org/theb/ssh/PasswordDialog.java @@ -18,7 +18,7 @@ */ package org.theb.ssh; -import org.theb.ssh.R; +import org.connectbot.R; import android.app.Activity; import android.content.Intent; diff --git a/src/org/theb/ssh/Pubkey.java b/src/org/theb/ssh/Pubkey.java index 95abba7..b39bcab 100644 --- a/src/org/theb/ssh/Pubkey.java +++ b/src/org/theb/ssh/Pubkey.java @@ -26,7 +26,7 @@ import java.security.SecureRandom; import java.security.Security; import java.util.concurrent.Semaphore; -import org.theb.ssh.R; +import org.connectbot.R; import android.app.Activity; import android.content.Intent; diff --git a/src/org/theb/ssh/SecureShell.java b/src/org/theb/ssh/SecureShell.java index e2bb4f4..9c2d125 100644 --- a/src/org/theb/ssh/SecureShell.java +++ b/src/org/theb/ssh/SecureShell.java @@ -21,7 +21,7 @@ package org.theb.ssh; import java.io.IOException; import java.io.OutputStream; -import org.theb.ssh.R; +import org.connectbot.R; import org.theb.provider.HostDb; import com.trilead.ssh2.ConnectionMonitor; diff --git a/src/org/theb/ssh/TouchEntropy.java b/src/org/theb/ssh/TouchEntropy.java index fc633b0..772585e 100644 --- a/src/org/theb/ssh/TouchEntropy.java +++ b/src/org/theb/ssh/TouchEntropy.java @@ -1,6 +1,6 @@ package org.theb.ssh; -import org.theb.ssh.R; +import org.connectbot.R; import android.app.Activity; import android.content.Context; |