diff src/com/five_ten_sg/connectbot/util/HostDatabase.java @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children ce8f13242339
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/five_ten_sg/connectbot/util/HostDatabase.java	Thu May 22 10:41:19 2014 -0700
@@ -0,0 +1,782 @@
+/*
+ * ConnectBot: simple, powerful, open-source SSH client for Android
+ * Copyright 2007 Kenny Root, Jeffrey Sharkey
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.five_ten_sg.connectbot.util;
+
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.five_ten_sg.connectbot.bean.HostBean;
+import com.five_ten_sg.connectbot.bean.PortForwardBean;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteException;
+import android.util.Log;
+
+import com.trilead.ssh2.KnownHosts;
+
+/**
+ * Contains information about various SSH hosts, include public hostkey if known
+ * from previous sessions.
+ *
+ * @author jsharkey
+ */
+public class HostDatabase extends RobustSQLiteOpenHelper {
+
+    public final static String TAG = "ConnectBot.HostDatabase";
+
+    public final static String DB_NAME = "hosts";
+    public final static int DB_VERSION = 25;
+
+    public final static String TABLE_HOSTS = "hosts";
+    public final static String FIELD_HOST_NICKNAME = "nickname";
+    public final static String FIELD_HOST_PROTOCOL = "protocol";
+    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_HOSTKEYALGO = "hostkeyalgo";
+    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 FIELD_HOST_USEKEYS = "usekeys";
+    public final static String FIELD_HOST_USEAUTHAGENT = "useauthagent";
+    public final static String FIELD_HOST_POSTLOGIN = "postlogin";
+    public final static String FIELD_HOST_PUBKEYID = "pubkeyid";
+    public final static String FIELD_HOST_WANTSESSION = "wantsession";
+    public final static String FIELD_HOST_DELKEY = "delkey";
+    public final static String FIELD_HOST_FONTSIZE = "fontsize";
+    public final static String FIELD_HOST_COMPRESSION = "compression";
+    public final static String FIELD_HOST_HTTPPROXY = "httpproxy";
+    public final static String FIELD_HOST_ENCODING = "encoding";
+    public final static String FIELD_HOST_STAYCONNECTED = "stayconnected";
+    public final static String FIELD_HOST_WANTX11FORWARD = "wantx11forward";
+    public final static String FIELD_HOST_X11HOST = "x11host";
+    public final static String FIELD_HOST_X11PORT = "x11port";
+    public final static String FIELD_HOST_MONITOR = "monitor";
+
+    public final static String TABLE_PORTFORWARDS = "portforwards";
+    public final static String FIELD_PORTFORWARD_HOSTID = "hostid";
+    public final static String FIELD_PORTFORWARD_NICKNAME = "nickname";
+    public final static String FIELD_PORTFORWARD_TYPE = "type";
+    public final static String FIELD_PORTFORWARD_SOURCEPORT = "sourceport";
+    public final static String FIELD_PORTFORWARD_DESTADDR = "destaddr";
+    public final static String FIELD_PORTFORWARD_DESTPORT = "destport";
+
+    public final static String TABLE_COLORS = "colors";
+    public final static String FIELD_COLOR_SCHEME = "scheme";
+    public final static String FIELD_COLOR_NUMBER = "number";
+    public final static String FIELD_COLOR_VALUE = "value";
+
+    public final static String TABLE_COLOR_DEFAULTS = "colorDefaults";
+    public final static String FIELD_COLOR_FG = "fg";
+    public final static String FIELD_COLOR_BG = "bg";
+
+    public final static int DEFAULT_FG_COLOR = 7;
+    public final static int DEFAULT_BG_COLOR = 0;
+
+    public final static String COLOR_RED = "red";
+    public final static String COLOR_GREEN = "green";
+    public final static String COLOR_BLUE = "blue";
+    public final static String COLOR_GRAY = "gray";
+
+    public final static String PORTFORWARD_LOCAL = "local";
+    public final static String PORTFORWARD_REMOTE = "remote";
+    public final static String PORTFORWARD_DYNAMIC4 = "dynamic4";
+    public final static String PORTFORWARD_DYNAMIC5 = "dynamic5";
+
+    public final static String DELKEY_DEL = "del";
+    public final static String DELKEY_BACKSPACE = "backspace";
+
+    public final static String AUTHAGENT_NO = "no";
+    public final static String AUTHAGENT_CONFIRM = "confirm";
+    public final static String AUTHAGENT_YES = "yes";
+
+    public final static String ENCODING_DEFAULT = Charset.defaultCharset().name();
+
+    public final static String X11HOST_DEFAULT = "localhost";
+    public final static int X11PORT_DEFAULT = 6000;
+
+    public final static long PUBKEYID_NEVER = -2;
+    public final static long PUBKEYID_ANY = -1;
+
+    public static final int DEFAULT_COLOR_SCHEME = 0;
+
+    // Table creation strings
+    public static final String CREATE_TABLE_COLOR_DEFAULTS =
+        "CREATE TABLE " + TABLE_COLOR_DEFAULTS
+        + " (" + FIELD_COLOR_SCHEME + " INTEGER NOT NULL, "
+        + FIELD_COLOR_FG + " INTEGER NOT NULL DEFAULT " + DEFAULT_FG_COLOR + ", "
+        + FIELD_COLOR_BG + " INTEGER NOT NULL DEFAULT " + DEFAULT_BG_COLOR + ")";
+    public static final String CREATE_TABLE_COLOR_DEFAULTS_INDEX =
+        "CREATE INDEX " + TABLE_COLOR_DEFAULTS + FIELD_COLOR_SCHEME + "index ON "
+        + TABLE_COLOR_DEFAULTS + " (" + FIELD_COLOR_SCHEME + ");";
+
+    private static final String WHERE_SCHEME_AND_COLOR = FIELD_COLOR_SCHEME + " = ? AND "
+            + FIELD_COLOR_NUMBER + " = ?";
+
+    static {
+        addTableName(TABLE_HOSTS);
+        addTableName(TABLE_PORTFORWARDS);
+        addIndexName(TABLE_PORTFORWARDS + FIELD_PORTFORWARD_HOSTID + "index");
+        addTableName(TABLE_COLORS);
+        addIndexName(TABLE_COLORS + FIELD_COLOR_SCHEME + "index");
+        addTableName(TABLE_COLOR_DEFAULTS);
+        addIndexName(TABLE_COLOR_DEFAULTS + FIELD_COLOR_SCHEME + "index");
+    }
+
+    public static final Object[] dbLock = new Object[0];
+
+    public HostDatabase(Context context) {
+        super(context, DB_NAME, null, DB_VERSION);
+        getWritableDatabase().close();
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        super.onCreate(db);
+        db.execSQL("CREATE TABLE " + TABLE_HOSTS
+                   + " (_id INTEGER PRIMARY KEY, "
+                   + FIELD_HOST_NICKNAME + " TEXT, "
+                   + FIELD_HOST_PROTOCOL + " TEXT DEFAULT 'ssh', "
+                   + FIELD_HOST_USERNAME + " TEXT, "
+                   + FIELD_HOST_HOSTNAME + " TEXT, "
+                   + FIELD_HOST_PORT + " INTEGER, "
+                   + FIELD_HOST_HOSTKEYALGO + " TEXT, "
+                   + FIELD_HOST_HOSTKEY + " BLOB, "
+                   + FIELD_HOST_LASTCONNECT + " INTEGER, "
+                   + FIELD_HOST_COLOR + " TEXT, "
+                   + FIELD_HOST_USEKEYS + " TEXT, "
+                   + FIELD_HOST_USEAUTHAGENT + " TEXT, "
+                   + FIELD_HOST_POSTLOGIN + " TEXT, "
+                   + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY + ", "
+                   + FIELD_HOST_DELKEY + " TEXT DEFAULT '" + DELKEY_DEL + "', "
+                   + FIELD_HOST_FONTSIZE + " INTEGER, "
+                   + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "', "
+                   + FIELD_HOST_COMPRESSION + " TEXT DEFAULT '" + Boolean.toString(false) + "', "
+                   + FIELD_HOST_HTTPPROXY + " TEXT, "
+                   + FIELD_HOST_ENCODING + " TEXT DEFAULT '" + ENCODING_DEFAULT + "', "
+                   + FIELD_HOST_STAYCONNECTED + " TEXT, "
+                   + FIELD_HOST_WANTX11FORWARD + " TEXT DEFAULT '" + Boolean.toString(false) + "', "
+                   + FIELD_HOST_X11HOST + " TEXT DEFAULT '" + X11HOST_DEFAULT + "', "
+                   + FIELD_HOST_X11PORT + " INTEGER DEFAULT " + X11PORT_DEFAULT + ", "
+                   + FIELD_HOST_MONITOR + " TEXT)");
+        db.execSQL("CREATE TABLE " + TABLE_PORTFORWARDS
+                   + " (_id INTEGER PRIMARY KEY, "
+                   + FIELD_PORTFORWARD_HOSTID + " INTEGER, "
+                   + FIELD_PORTFORWARD_NICKNAME + " TEXT, "
+                   + FIELD_PORTFORWARD_TYPE + " TEXT NOT NULL DEFAULT " + PORTFORWARD_LOCAL + ", "
+                   + FIELD_PORTFORWARD_SOURCEPORT + " INTEGER NOT NULL DEFAULT 8080, "
+                   + FIELD_PORTFORWARD_DESTADDR + " TEXT, "
+                   + FIELD_PORTFORWARD_DESTPORT + " TEXT)");
+        db.execSQL("CREATE INDEX " + TABLE_PORTFORWARDS + FIELD_PORTFORWARD_HOSTID + "index ON "
+                   + TABLE_PORTFORWARDS + " (" + FIELD_PORTFORWARD_HOSTID + ");");
+        db.execSQL("CREATE TABLE " + TABLE_COLORS
+                   + " (_id INTEGER PRIMARY KEY, "
+                   + FIELD_COLOR_NUMBER + " INTEGER, "
+                   + FIELD_COLOR_VALUE + " INTEGER, "
+                   + FIELD_COLOR_SCHEME + " INTEGER)");
+        db.execSQL("CREATE INDEX " + TABLE_COLORS + FIELD_COLOR_SCHEME + "index ON "
+                   + TABLE_COLORS + " (" + FIELD_COLOR_SCHEME + ");");
+        db.execSQL(CREATE_TABLE_COLOR_DEFAULTS);
+        db.execSQL(CREATE_TABLE_COLOR_DEFAULTS_INDEX);
+    }
+
+    @Override
+    public void onRobustUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) throws SQLiteException {
+        // Versions of the database before the Android Market release will be
+        // shot without warning.
+        if (oldVersion <= 9) {
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_HOSTS);
+            onCreate(db);
+            return;
+        }
+
+        switch (oldVersion) {
+            case 10:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY);
+
+            case 11:
+                db.execSQL("CREATE TABLE " + TABLE_PORTFORWARDS
+                           + " (_id INTEGER PRIMARY KEY, "
+                           + FIELD_PORTFORWARD_HOSTID + " INTEGER, "
+                           + FIELD_PORTFORWARD_NICKNAME + " TEXT, "
+                           + FIELD_PORTFORWARD_TYPE + " TEXT NOT NULL DEFAULT " + PORTFORWARD_LOCAL + ", "
+                           + FIELD_PORTFORWARD_SOURCEPORT + " INTEGER NOT NULL DEFAULT 8080, "
+                           + FIELD_PORTFORWARD_DESTADDR + " TEXT, "
+                           + FIELD_PORTFORWARD_DESTPORT + " INTEGER)");
+
+            case 12:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "'");
+
+            case 13:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_COMPRESSION + " TEXT DEFAULT '" + Boolean.toString(false) + "'");
+
+            case 14:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_ENCODING + " TEXT DEFAULT '" + ENCODING_DEFAULT + "'");
+
+            case 15:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_PROTOCOL + " TEXT DEFAULT 'ssh'");
+
+            case 16:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_DELKEY + " TEXT DEFAULT '" + DELKEY_DEL + "'");
+
+            case 17:
+                db.execSQL("CREATE INDEX " + TABLE_PORTFORWARDS + FIELD_PORTFORWARD_HOSTID + "index ON "
+                           + TABLE_PORTFORWARDS + " (" + FIELD_PORTFORWARD_HOSTID + ");");
+                // Add colors
+                db.execSQL("CREATE TABLE " + TABLE_COLORS
+                           + " (_id INTEGER PRIMARY KEY, "
+                           + FIELD_COLOR_NUMBER + " INTEGER, "
+                           + FIELD_COLOR_VALUE + " INTEGER, "
+                           + FIELD_COLOR_SCHEME + " INTEGER)");
+                db.execSQL("CREATE INDEX " + TABLE_COLORS + FIELD_COLOR_SCHEME + "index ON "
+                           + TABLE_COLORS + " (" + FIELD_COLOR_SCHEME + ");");
+
+            case 18:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_USEAUTHAGENT + " TEXT DEFAULT '" + AUTHAGENT_NO + "'");
+
+            case 19:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_STAYCONNECTED + " TEXT");
+
+            case 20:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_FONTSIZE + " INTEGER");
+
+            case 21:
+                db.execSQL("DROP TABLE " + TABLE_COLOR_DEFAULTS);
+                db.execSQL(CREATE_TABLE_COLOR_DEFAULTS);
+                db.execSQL(CREATE_TABLE_COLOR_DEFAULTS_INDEX);
+
+            case 22:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_WANTX11FORWARD + " TEXT DEFAULT '" + Boolean.toString(false) + "'");
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_X11HOST + " TEXT DEFAULT '" + X11HOST_DEFAULT + "'");
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_X11PORT + " INTEGER DEFAULT " + X11PORT_DEFAULT);
+
+            case 23:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_HTTPPROXY + " TEXT");
+
+            case 24:
+                db.execSQL("ALTER TABLE " + TABLE_HOSTS
+                           + " ADD COLUMN " + FIELD_HOST_MONITOR + " TEXT");
+        }
+    }
+
+    /**
+     * Touch a specific host to update its "last connected" field.
+     * @param nickname Nickname field of host to update
+     */
+    public void touchHost(HostBean host) {
+        long now = System.currentTimeMillis() / 1000;
+        ContentValues values = new ContentValues();
+        values.put(FIELD_HOST_LASTCONNECT, now);
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = this.getWritableDatabase();
+            db.update(TABLE_HOSTS, values, "_id = ?", new String[] { String.valueOf(host.getId()) });
+        }
+    }
+
+    /**
+     * Create a new host using the given parameters.
+     */
+    public HostBean saveHost(HostBean host) {
+        long id;
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = this.getWritableDatabase();
+            id = db.insert(TABLE_HOSTS, null, host.getValues());
+        }
+
+        host.setId(id);
+        return host;
+    }
+
+    /**
+     * Update a field in a host record.
+     */
+    public boolean updateFontSize(HostBean host) {
+        long id = host.getId();
+
+        if (id < 0)
+            return false;
+
+        ContentValues updates = new ContentValues();
+        updates.put(FIELD_HOST_FONTSIZE, host.getFontSize());
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = getWritableDatabase();
+            db.update(TABLE_HOSTS, updates, "_id = ?",
+                      new String[] { String.valueOf(id) });
+        }
+
+        return true;
+    }
+
+    /**
+     * Delete a specific host by its <code>_id</code> value.
+     */
+    public void deleteHost(HostBean host) {
+        if (host.getId() < 0)
+            return;
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = this.getWritableDatabase();
+            db.delete(TABLE_HOSTS, "_id = ?", new String[] { String.valueOf(host.getId()) });
+        }
+    }
+
+    /**
+     * Return a cursor that contains information about all known hosts.
+     * @param sortColors If true, sort by color, otherwise sort by nickname.
+     */
+    public List<HostBean> getHosts(boolean sortColors) {
+        String sortField = sortColors ? FIELD_HOST_COLOR : FIELD_HOST_NICKNAME;
+        List<HostBean> hosts;
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = this.getReadableDatabase();
+            Cursor c = db.query(TABLE_HOSTS, null, null, null, null, null, sortField + " ASC");
+            hosts = createHostBeans(c);
+            c.close();
+        }
+
+        return hosts;
+    }
+
+    /**
+     * @param hosts
+     * @param c
+     */
+    private List<HostBean> createHostBeans(Cursor c) {
+        List<HostBean> hosts = new LinkedList<HostBean>();
+        final int COL_ID = c.getColumnIndexOrThrow("_id"),
+                  COL_NICKNAME = c.getColumnIndexOrThrow(FIELD_HOST_NICKNAME),
+                  COL_PROTOCOL = c.getColumnIndexOrThrow(FIELD_HOST_PROTOCOL),
+                  COL_USERNAME = c.getColumnIndexOrThrow(FIELD_HOST_USERNAME),
+                  COL_HOSTNAME = c.getColumnIndexOrThrow(FIELD_HOST_HOSTNAME),
+                  COL_PORT = c.getColumnIndexOrThrow(FIELD_HOST_PORT),
+                  COL_LASTCONNECT = c.getColumnIndexOrThrow(FIELD_HOST_LASTCONNECT),
+                  COL_COLOR = c.getColumnIndexOrThrow(FIELD_HOST_COLOR),
+                  COL_USEKEYS = c.getColumnIndexOrThrow(FIELD_HOST_USEKEYS),
+                  COL_USEAUTHAGENT = c.getColumnIndexOrThrow(FIELD_HOST_USEAUTHAGENT),
+                  COL_POSTLOGIN = c.getColumnIndexOrThrow(FIELD_HOST_POSTLOGIN),
+                  COL_PUBKEYID = c.getColumnIndexOrThrow(FIELD_HOST_PUBKEYID),
+                  COL_WANTSESSION = c.getColumnIndexOrThrow(FIELD_HOST_WANTSESSION),
+                  COL_DELKEY = c.getColumnIndexOrThrow(FIELD_HOST_DELKEY),
+                  COL_FONTSIZE = c.getColumnIndexOrThrow(FIELD_HOST_FONTSIZE),
+                  COL_COMPRESSION = c.getColumnIndexOrThrow(FIELD_HOST_COMPRESSION),
+                  COL_HTTPPROXY = c.getColumnIndexOrThrow(FIELD_HOST_HTTPPROXY),
+                  COL_ENCODING = c.getColumnIndexOrThrow(FIELD_HOST_ENCODING),
+                  COL_STAYCONNECTED = c.getColumnIndexOrThrow(FIELD_HOST_STAYCONNECTED),
+                  COL_WANTX11FORWARD = c.getColumnIndexOrThrow(FIELD_HOST_WANTX11FORWARD),
+                  COL_X11HOST = c.getColumnIndexOrThrow(FIELD_HOST_X11HOST),
+                  COL_X11PORT = c.getColumnIndexOrThrow(FIELD_HOST_X11PORT),
+                  COL_MONITOR = c.getColumnIndexOrThrow(FIELD_HOST_MONITOR);
+
+        while (c.moveToNext()) {
+            HostBean host = new HostBean();
+            host.setId(c.getLong(COL_ID));
+            host.setNickname(c.getString(COL_NICKNAME));
+            host.setProtocol(c.getString(COL_PROTOCOL));
+            host.setUsername(c.getString(COL_USERNAME));
+            host.setHostname(c.getString(COL_HOSTNAME));
+            host.setPort(c.getInt(COL_PORT));
+            host.setLastConnect(c.getLong(COL_LASTCONNECT));
+            host.setColor(c.getString(COL_COLOR));
+            host.setUseKeys(Boolean.valueOf(c.getString(COL_USEKEYS)));
+            host.setUseAuthAgent(c.getString(COL_USEAUTHAGENT));
+            host.setPostLogin(c.getString(COL_POSTLOGIN));
+            host.setPubkeyId(c.getLong(COL_PUBKEYID));
+            host.setWantSession(Boolean.valueOf(c.getString(COL_WANTSESSION)));
+            host.setDelKey(c.getString(COL_DELKEY));
+            host.setFontSize(c.getInt(COL_FONTSIZE));
+            host.setCompression(Boolean.valueOf(c.getString(COL_COMPRESSION)));
+            host.setHttpproxy(c.getString(COL_HTTPPROXY));
+            host.setEncoding(c.getString(COL_ENCODING));
+            host.setStayConnected(Boolean.valueOf(c.getString(COL_STAYCONNECTED)));
+            host.setWantX11Forward(Boolean.valueOf(c.getString(COL_WANTX11FORWARD)));
+            host.setX11Host(c.getString(COL_X11HOST));
+            host.setX11Port(c.getInt(COL_X11PORT));
+            host.setMonitor(c.getString(COL_MONITOR));
+            hosts.add(host);
+        }
+
+        return hosts;
+    }
+
+    /**
+     * @param c
+     * @return
+     */
+    private HostBean getFirstHostBean(Cursor c) {
+        HostBean host = null;
+        List<HostBean> hosts = createHostBeans(c);
+
+        if (hosts.size() > 0)
+            host = hosts.get(0);
+
+        c.close();
+        return host;
+    }
+
+    /**
+     * @param nickname
+     * @param protocol
+     * @param username
+     * @param hostname
+     * @param hostname2
+     * @param port
+     * @return
+     */
+    public HostBean findHost(Map<String, String> selection) {
+        StringBuilder selectionBuilder = new StringBuilder();
+        Iterator<Entry<String, String>> i = selection.entrySet().iterator();
+        List<String> selectionValuesList = new LinkedList<String>();
+        int n = 0;
+
+        while (i.hasNext()) {
+            Entry<String, String> entry = i.next();
+
+            if (entry.getValue() == null)
+                continue;
+
+            if (n++ > 0)
+                selectionBuilder.append(" AND ");
+
+            selectionBuilder.append(entry.getKey())
+            .append(" = ?");
+            selectionValuesList.add(entry.getValue());
+        }
+
+        String selectionValues[] = new String[selectionValuesList.size()];
+        selectionValuesList.toArray(selectionValues);
+        selectionValuesList = null;
+        HostBean host;
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = getReadableDatabase();
+            Cursor c = db.query(TABLE_HOSTS, null,
+                                selectionBuilder.toString(),
+                                selectionValues,
+                                null, null, null);
+            host = getFirstHostBean(c);
+        }
+
+        return host;
+    }
+
+    /**
+     * @param hostId
+     * @return
+     */
+    public HostBean findHostById(long hostId) {
+        HostBean host;
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = getReadableDatabase();
+            Cursor c = db.query(TABLE_HOSTS, null,
+                                "_id = ?", new String[] { String.valueOf(hostId) },
+                                null, null, null);
+            host = getFirstHostBean(c);
+        }
+
+        return host;
+    }
+
+    /**
+     * Record the given hostkey into database under this nickname.
+     * @param hostname
+     * @param port
+     * @param hostkeyalgo
+     * @param hostkey
+     */
+    public void saveKnownHost(String hostname, int port, String hostkeyalgo, byte[] hostkey) {
+        ContentValues values = new ContentValues();
+        values.put(FIELD_HOST_HOSTKEYALGO, hostkeyalgo);
+        values.put(FIELD_HOST_HOSTKEY, hostkey);
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = getReadableDatabase();
+            db.update(TABLE_HOSTS, values,
+                      FIELD_HOST_HOSTNAME + " = ? AND " + FIELD_HOST_PORT + " = ?",
+                      new String[] { hostname, String.valueOf(port) });
+            Log.d(TAG, String.format("Finished saving hostkey information for '%s'", hostname));
+        }
+    }
+
+    /**
+     * Build list of known hosts for Trilead library.
+     * @return
+     */
+    public KnownHosts getKnownHosts() {
+        KnownHosts known = new KnownHosts();
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = this.getReadableDatabase();
+            Cursor c = db.query(TABLE_HOSTS, new String[] { FIELD_HOST_HOSTNAME,
+                                FIELD_HOST_PORT, FIELD_HOST_HOSTKEYALGO, FIELD_HOST_HOSTKEY
+                                                          },
+                                null, null, null, null, null);
+
+            if (c != null) {
+                int COL_HOSTNAME = c.getColumnIndexOrThrow(FIELD_HOST_HOSTNAME),
+                    COL_PORT = c.getColumnIndexOrThrow(FIELD_HOST_PORT),
+                    COL_HOSTKEYALGO = c.getColumnIndexOrThrow(FIELD_HOST_HOSTKEYALGO),
+                    COL_HOSTKEY = c.getColumnIndexOrThrow(FIELD_HOST_HOSTKEY);
+
+                while (c.moveToNext()) {
+                    String hostname = c.getString(COL_HOSTNAME),
+                           hostkeyalgo = c.getString(COL_HOSTKEYALGO);
+                    int port = c.getInt(COL_PORT);
+                    byte[] hostkey = c.getBlob(COL_HOSTKEY);
+
+                    if (hostkeyalgo == null || hostkeyalgo.length() == 0) continue;
+
+                    if (hostkey == null || hostkey.length == 0) continue;
+
+                    try {
+                        known.addHostkey(new String[] { String.format("%s:%d", hostname, port) }, hostkeyalgo, hostkey);
+                    }
+                    catch (Exception e) {
+                        Log.e(TAG, "Problem while adding a known host from database", e);
+                    }
+                }
+
+                c.close();
+            }
+        }
+
+        return known;
+    }
+
+    /**
+     * Unset any hosts using a pubkey ID that has been deleted.
+     * @param pubkeyId
+     */
+    public void stopUsingPubkey(long pubkeyId) {
+        if (pubkeyId < 0) return;
+
+        ContentValues values = new ContentValues();
+        values.put(FIELD_HOST_PUBKEYID, PUBKEYID_ANY);
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = this.getWritableDatabase();
+            db.update(TABLE_HOSTS, values, FIELD_HOST_PUBKEYID + " = ?", new String[] { String.valueOf(pubkeyId) });
+        }
+
+        Log.d(TAG, String.format("Set all hosts using pubkey id %d to -1", pubkeyId));
+    }
+
+    /*
+     * Methods for dealing with port forwards attached to hosts
+     */
+
+    /**
+     * Returns a list of all the port forwards associated with a particular host ID.
+     * @param host the host for which we want the port forward list
+     * @return port forwards associated with host ID
+     */
+    public List<PortForwardBean> getPortForwardsForHost(HostBean host) {
+        List<PortForwardBean> portForwards = new LinkedList<PortForwardBean>();
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = this.getReadableDatabase();
+            Cursor c = db.query(TABLE_PORTFORWARDS, new String[] {
+                                    "_id", FIELD_PORTFORWARD_NICKNAME, FIELD_PORTFORWARD_TYPE, FIELD_PORTFORWARD_SOURCEPORT,
+                                    FIELD_PORTFORWARD_DESTADDR, FIELD_PORTFORWARD_DESTPORT
+                                },
+                                FIELD_PORTFORWARD_HOSTID + " = ?", new String[] { String.valueOf(host.getId()) },
+                                null, null, null);
+
+            while (c.moveToNext()) {
+                PortForwardBean pfb = new PortForwardBean(
+                    c.getInt(0),
+                    host.getId(),
+                    c.getString(1),
+                    c.getString(2),
+                    c.getInt(3),
+                    c.getString(4),
+                    c.getInt(5));
+                portForwards.add(pfb);
+            }
+
+            c.close();
+        }
+
+        return portForwards;
+    }
+
+    /**
+     * Update the parameters of a port forward in the database.
+     * @param pfb {@link PortForwardBean} to save
+     * @return true on success
+     */
+    public boolean savePortForward(PortForwardBean pfb) {
+        boolean success = false;
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = getWritableDatabase();
+
+            if (pfb.getId() < 0) {
+                long id = db.insert(TABLE_PORTFORWARDS, null, pfb.getValues());
+                pfb.setId(id);
+                success = true;
+            }
+            else {
+                if (db.update(TABLE_PORTFORWARDS, pfb.getValues(), "_id = ?", new String[] { String.valueOf(pfb.getId()) }) > 0)
+                    success = true;
+            }
+        }
+
+        return success;
+    }
+
+    /**
+     * Deletes a port forward from the database.
+     * @param pfb {@link PortForwardBean} to delete
+     */
+    public void deletePortForward(PortForwardBean pfb) {
+        if (pfb.getId() < 0)
+            return;
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = this.getWritableDatabase();
+            db.delete(TABLE_PORTFORWARDS, "_id = ?", new String[] { String.valueOf(pfb.getId()) });
+        }
+    }
+
+    public Integer[] getColorsForScheme(int scheme) {
+        Integer[] colors = Colors.defaults.clone();
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = getReadableDatabase();
+            Cursor c = db.query(TABLE_COLORS, new String[] {
+                                    FIELD_COLOR_NUMBER, FIELD_COLOR_VALUE
+                                },
+                                FIELD_COLOR_SCHEME + " = ?",
+                                new String[] { String.valueOf(scheme) },
+                                null, null, null);
+
+            while (c.moveToNext()) {
+                colors[c.getInt(0)] = Integer.valueOf(c.getInt(1));
+            }
+
+            c.close();
+        }
+
+        return colors;
+    }
+
+    public void setColorForScheme(int scheme, int number, int value) {
+        final SQLiteDatabase db;
+        final String[] whereArgs = new String[] { String.valueOf(scheme), String.valueOf(number) };
+
+        if (value == Colors.defaults[number]) {
+            synchronized (dbLock) {
+                db = getWritableDatabase();
+                db.delete(TABLE_COLORS,
+                          WHERE_SCHEME_AND_COLOR, whereArgs);
+            }
+        }
+        else {
+            final ContentValues values = new ContentValues();
+            values.put(FIELD_COLOR_VALUE, value);
+
+            synchronized (dbLock) {
+                db = getWritableDatabase();
+                final int rowsAffected = db.update(TABLE_COLORS, values,
+                                                   WHERE_SCHEME_AND_COLOR, whereArgs);
+
+                if (rowsAffected == 0) {
+                    values.put(FIELD_COLOR_SCHEME, scheme);
+                    values.put(FIELD_COLOR_NUMBER, number);
+                    db.insert(TABLE_COLORS, null, values);
+                }
+            }
+        }
+    }
+
+    public void setGlobalColor(int number, int value) {
+        setColorForScheme(DEFAULT_COLOR_SCHEME, number, value);
+    }
+
+    public int[] getDefaultColorsForScheme(int scheme) {
+        int[] colors = new int[] { DEFAULT_FG_COLOR, DEFAULT_BG_COLOR };
+
+        synchronized (dbLock) {
+            SQLiteDatabase db = getReadableDatabase();
+            Cursor c = db.query(TABLE_COLOR_DEFAULTS,
+                                new String[] { FIELD_COLOR_FG, FIELD_COLOR_BG },
+                                FIELD_COLOR_SCHEME + " = ?",
+                                new String[] { String.valueOf(scheme) },
+                                null, null, null);
+
+            if (c.moveToFirst()) {
+                colors[0] = c.getInt(0);
+                colors[1] = c.getInt(1);
+            }
+
+            c.close();
+        }
+
+        return colors;
+    }
+
+    public int[] getGlobalDefaultColors() {
+        return getDefaultColorsForScheme(DEFAULT_COLOR_SCHEME);
+    }
+
+    public void setDefaultColorsForScheme(int scheme, int fg, int bg) {
+        SQLiteDatabase db;
+        String schemeWhere = null;
+        String[] whereArgs;
+        schemeWhere = FIELD_COLOR_SCHEME + " = ?";
+        whereArgs = new String[] { String.valueOf(scheme) };
+        ContentValues values = new ContentValues();
+        values.put(FIELD_COLOR_FG, fg);
+        values.put(FIELD_COLOR_BG, bg);
+
+        synchronized (dbLock) {
+            db = getWritableDatabase();
+            int rowsAffected = db.update(TABLE_COLOR_DEFAULTS, values,
+                                         schemeWhere, whereArgs);
+
+            if (rowsAffected == 0) {
+                values.put(FIELD_COLOR_SCHEME, scheme);
+                db.insert(TABLE_COLOR_DEFAULTS, null, values);
+            }
+        }
+    }
+}