/*
* 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 org.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 org.connectbot.bean.HostBean;
import org.connectbot.bean.PortForwardBean;
import org.connectbot.data.ColorStorage;
import org.connectbot.data.HostStorage;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.support.annotation.VisibleForTesting;
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 implements HostStorage, ColorStorage {
public final static String TAG = "CB.HostDatabase";
public final static String DB_NAME = "hosts";
public final static int DB_VERSION = 24;
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_ENCODING = "encoding";
public final static String FIELD_HOST_STAYCONNECTED = "stayconnected";
public final static String FIELD_HOST_QUICKDISCONNECT = "quickdisconnect";
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 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");
}
/** Used during upgrades from DB version 23 to 24. */
private final float displayDensity;
private static final Object sInstanceLock = new Object();
private static HostDatabase sInstance;
private final SQLiteDatabase mDb;
public static HostDatabase get(Context context) {
synchronized (sInstanceLock) {
if (sInstance != null) {
return sInstance;
}
sInstance = new HostDatabase(context.getApplicationContext());
return sInstance;
}
}
private HostDatabase(Context context) {
this(context, DB_NAME);
}
private HostDatabase(Context context, String dbName) {
super(context, dbName, null, DB_VERSION);
this.displayDensity = context.getResources().getDisplayMetrics().density;
mDb = getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
super.onCreate(db);
createTables(db);
}
private void createTables(SQLiteDatabase 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_ENCODING + " TEXT DEFAULT '" + ENCODING_DEFAULT + "', "
+ FIELD_HOST_STAYCONNECTED + " TEXT DEFAULT '" + Boolean.toString(false) + "', "
+ FIELD_HOST_QUICKDISCONNECT + " TEXT DEFAULT '" + Boolean.toString(false) + "')");
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);
}
@VisibleForTesting
public void resetDatabase() {
try {
mDb.beginTransaction();
mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_HOSTS);
mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_PORTFORWARDS);
mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_COLORS);
mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_COLOR_DEFAULTS);
createTables(mDb);
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
}
@VisibleForTesting
public static void resetInMemoryInstance(Context context) {
get(context).resetDatabase();
}
@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_QUICKDISCONNECT + " TEXT DEFAULT '" + Boolean.toString(false) + "'");
case 23:
db.execSQL("UPDATE " + TABLE_HOSTS
+ " SET " + FIELD_HOST_FONTSIZE + " = " + FIELD_HOST_FONTSIZE + " / " + displayDensity);
}
}
/**
* Touch a specific host to update its "last connected" field.
* @param host host to update
*/
public void touchHost(HostBean host) {
long now = System.currentTimeMillis() / 1000;
ContentValues values = new ContentValues();
values.put(FIELD_HOST_LASTCONNECT, now);
mDb.beginTransaction();
try {
mDb.update(TABLE_HOSTS, values, "_id = ?", new String[] {String.valueOf(host.getId())});
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
}
/**
* Create a new or update an existing {@code host}.
*/
public HostBean saveHost(HostBean host) {
long id = host.getId();
mDb.beginTransaction();
try {
if (id == -1) {
id = mDb.insert(TABLE_HOSTS, null, host.getValues());
} else {
mDb.update(TABLE_HOSTS, host.getValues(), "_id = ?", new String[] {String.valueOf(id)});
}
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
host.setId(id);
return host;
}
/**
* Delete a specific host by its _id
value.
*/
public void deleteHost(HostBean host) {
if (host.getId() < 0) {
return;
}
mDb.beginTransaction();
try {
mDb.delete(TABLE_HOSTS, "_id = ?", new String[] {String.valueOf(host.getId())});
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
}
/**
* Return a cursor that contains information about all known hosts.
* @param sortColors If true, sort by color, otherwise sort by nickname.
*/
public List getHosts(boolean sortColors) {
String sortField = sortColors ? FIELD_HOST_COLOR : FIELD_HOST_NICKNAME;
List hosts;
Cursor c = mDb.query(TABLE_HOSTS, null, null, null, null, null, sortField + " ASC");
hosts = createHostBeans(c);
c.close();
return hosts;
}
/**
* @param c cursor to read from
*/
private List createHostBeans(Cursor c) {
List hosts = new LinkedList();
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_ENCODING = c.getColumnIndexOrThrow(FIELD_HOST_ENCODING),
COL_STAYCONNECTED = c.getColumnIndexOrThrow(FIELD_HOST_STAYCONNECTED),
COL_QUICKDISCONNECT = c.getColumnIndexOrThrow(FIELD_HOST_QUICKDISCONNECT);
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.setEncoding(c.getString(COL_ENCODING));
host.setStayConnected(Boolean.valueOf(c.getString(COL_STAYCONNECTED)));
host.setQuickDisconnect(Boolean.valueOf(c.getString(COL_QUICKDISCONNECT)));
hosts.add(host);
}
return hosts;
}
/**
* @param c cursor with zero or more hosts
* @return the first host from the cursor or {@code null} if none.
*/
private HostBean getFirstHostBean(Cursor c) {
HostBean host = null;
List hosts = createHostBeans(c);
if (hosts.size() > 0)
host = hosts.get(0);
c.close();
return host;
}
/**
* @param selection parameters describing the desired host
* @return host matching selection or {@code null}.
*/
public HostBean findHost(Map selection) {
StringBuilder selectionBuilder = new StringBuilder();
Iterator> i = selection.entrySet().iterator();
List selectionValuesList = new LinkedList();
int n = 0;
while (i.hasNext()) {
Entry 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);
Cursor c = mDb.query(TABLE_HOSTS, null,
selectionBuilder.toString(),
selectionValues,
null, null, null);
HostBean host = getFirstHostBean(c);
return host;
}
/**
* @param hostId host id for the host
* @return host matching the hostId or {@code null} if none match
*/
public HostBean findHostById(long hostId) {
Cursor c = mDb.query(TABLE_HOSTS, null,
"_id = ?", new String[] {String.valueOf(hostId)},
null, null, null);
return getFirstHostBean(c);
}
/**
* Record the given hostkey into database under this nickname.
* @param hostname hostname to match
* @param port port to match
* @param hostkeyalgo algorithm for host key
* @param hostkey the bytes of the host key itself
*/
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);
int numUpdated;
mDb.beginTransaction();
try {
numUpdated = mDb.update(TABLE_HOSTS, values,
FIELD_HOST_HOSTNAME + " = ? AND " + FIELD_HOST_PORT + " = ?",
new String[]{hostname, String.valueOf(port)});
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
Log.d(TAG, String.format("Finished saving hostkey information for '%s' (affected %d entries)",
hostname, numUpdated));
}
/**
* Build list of known hosts for Trilead library.
* @return
*/
public KnownHosts getKnownHosts() {
KnownHosts known = new KnownHosts();
Cursor c = mDb.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);
String 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);
mDb.beginTransaction();
try {
mDb.update(TABLE_HOSTS, values, FIELD_HOST_PUBKEYID + " = ?", new String[] {String.valueOf(pubkeyId)});
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
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 or empty list if no match
*/
public List getPortForwardsForHost(HostBean host) {
List portForwards = new LinkedList();
if (host == null) {
return portForwards;
}
Cursor c = mDb.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) {
mDb.beginTransaction();
try {
if (pfb.getId() < 0) {
long addedId = mDb.insert(TABLE_PORTFORWARDS, null, pfb.getValues());
if (addedId == -1) {
return false;
}
pfb.setId(addedId);
} else {
if (mDb.update(TABLE_PORTFORWARDS, pfb.getValues(), "_id = ?", new String[] {String.valueOf(pfb.getId())}) <= 0) {
return false;
}
}
mDb.setTransactionSuccessful();
return true;
} finally {
mDb.endTransaction();
}
}
/**
* Deletes a port forward from the database.
* @param pfb {@link PortForwardBean} to delete
*/
public void deletePortForward(PortForwardBean pfb) {
if (pfb.getId() < 0) {
return;
}
mDb.beginTransaction();
try {
mDb.delete(TABLE_PORTFORWARDS, "_id = ?", new String[] {String.valueOf(pfb.getId())});
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
}
public int[] getColorsForScheme(int scheme) {
int[] colors = Colors.defaults.clone();
Cursor c = mDb.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]) {
mDb.beginTransaction();
try {
mDb.delete(TABLE_COLORS,
WHERE_SCHEME_AND_COLOR, whereArgs);
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
} else {
final ContentValues values = new ContentValues();
values.put(FIELD_COLOR_VALUE, value);
mDb.beginTransaction();
try {
final int rowsAffected = mDb.update(TABLE_COLORS, values,
WHERE_SCHEME_AND_COLOR, whereArgs);
if (rowsAffected == 0) {
values.put(FIELD_COLOR_SCHEME, scheme);
values.put(FIELD_COLOR_NUMBER, number);
mDb.insert(TABLE_COLORS, null, values);
}
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
}
}
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 };
Cursor c = mDb.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);
mDb.beginTransaction();
try {
int rowsAffected = mDb.update(TABLE_COLOR_DEFAULTS, values,
schemeWhere, whereArgs);
if (rowsAffected == 0) {
values.put(FIELD_COLOR_SCHEME, scheme);
mDb.insert(TABLE_COLOR_DEFAULTS, null, values);
}
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
}
}
}