2014-02-28 17:46:01 +00:00
package eu.siacs.conversations.persistance ;
2014-01-24 22:58:51 +00:00
2015-06-25 14:56:34 +00:00
import android.content.ContentValues ;
import android.content.Context ;
import android.database.Cursor ;
2015-07-20 12:56:41 +00:00
import android.database.DatabaseUtils ;
2015-06-25 14:56:34 +00:00
import android.database.sqlite.SQLiteDatabase ;
import android.database.sqlite.SQLiteOpenHelper ;
2017-01-25 12:22:20 +00:00
import android.os.Environment ;
2018-03-18 11:24:28 +00:00
import android.os.SystemClock ;
2015-06-25 14:56:34 +00:00
import android.util.Base64 ;
import android.util.Log ;
2016-09-16 09:07:52 +00:00
import org.json.JSONObject ;
2017-06-18 14:35:30 +00:00
import org.whispersystems.libsignal.SignalProtocolAddress ;
import org.whispersystems.libsignal.IdentityKey ;
import org.whispersystems.libsignal.IdentityKeyPair ;
import org.whispersystems.libsignal.InvalidKeyException ;
import org.whispersystems.libsignal.state.PreKeyRecord ;
import org.whispersystems.libsignal.state.SessionRecord ;
import org.whispersystems.libsignal.state.SignedPreKeyRecord ;
2015-06-25 14:56:34 +00:00
2015-12-23 18:18:53 +00:00
import java.io.ByteArrayInputStream ;
2017-01-25 12:22:20 +00:00
import java.io.File ;
2015-05-29 09:17:26 +00:00
import java.io.IOException ;
2015-12-23 16:41:26 +00:00
import java.security.cert.CertificateEncodingException ;
2015-12-23 18:18:53 +00:00
import java.security.cert.CertificateException ;
import java.security.cert.CertificateFactory ;
2015-12-23 16:41:26 +00:00
import java.security.cert.X509Certificate ;
2014-01-24 22:58:51 +00:00
import java.util.ArrayList ;
2016-11-14 21:27:41 +00:00
import java.util.HashMap ;
2015-06-29 11:53:39 +00:00
import java.util.HashSet ;
2015-09-20 21:17:32 +00:00
import java.util.Iterator ;
2014-01-24 22:58:51 +00:00
import java.util.List ;
2016-11-14 21:27:41 +00:00
import java.util.Map ;
2015-06-29 11:53:39 +00:00
import java.util.Set ;
2018-09-15 17:38:45 +00:00
import java.util.UUID ;
2014-03-11 16:47:05 +00:00
import java.util.concurrent.CopyOnWriteArrayList ;
2018-05-17 18:17:00 +00:00
2016-01-13 02:53:38 +00:00
import org.json.JSONException ;
2014-01-24 22:58:51 +00:00
2015-05-14 13:25:52 +00:00
import eu.siacs.conversations.Config ;
2015-05-29 09:17:26 +00:00
import eu.siacs.conversations.crypto.axolotl.AxolotlService ;
2016-11-14 21:27:41 +00:00
import eu.siacs.conversations.crypto.axolotl.FingerprintStatus ;
2015-07-28 20:00:54 +00:00
import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore ;
2014-02-28 17:46:01 +00:00
import eu.siacs.conversations.entities.Account ;
import eu.siacs.conversations.entities.Contact ;
import eu.siacs.conversations.entities.Conversation ;
import eu.siacs.conversations.entities.Message ;
2016-04-22 19:25:06 +00:00
import eu.siacs.conversations.entities.PresenceTemplate ;
2014-05-19 13:15:09 +00:00
import eu.siacs.conversations.entities.Roster ;
2016-01-13 02:53:38 +00:00
import eu.siacs.conversations.entities.ServiceDiscoveryResult ;
2018-11-25 19:47:50 +00:00
import eu.siacs.conversations.services.QuickConversationsService ;
2017-05-31 14:45:51 +00:00
import eu.siacs.conversations.services.ShortcutService ;
2017-06-25 16:18:13 +00:00
import eu.siacs.conversations.utils.CryptoHelper ;
2018-04-30 15:09:55 +00:00
import eu.siacs.conversations.utils.FtsUtils ;
2017-01-25 12:22:20 +00:00
import eu.siacs.conversations.utils.MimeUtils ;
2018-01-21 19:41:30 +00:00
import eu.siacs.conversations.utils.Resolver ;
2018-05-09 09:09:01 +00:00
import eu.siacs.conversations.xmpp.InvalidJid ;
2017-05-07 19:05:35 +00:00
import eu.siacs.conversations.xmpp.mam.MamReference ;
2018-03-05 17:30:40 +00:00
import rocks.xmpp.addr.Jid ;
2014-11-05 20:55:47 +00:00
2014-01-24 22:58:51 +00:00
public class DatabaseBackend extends SQLiteOpenHelper {
2014-01-26 02:27:55 +00:00
2014-01-24 22:58:51 +00:00
private static final String DATABASE_NAME = " history " ;
2018-11-25 19:47:50 +00:00
private static final int DATABASE_VERSION = 43 ;
2018-05-17 18:17:00 +00:00
private static DatabaseBackend instance = null ;
2014-05-19 13:15:09 +00:00
private static String CREATE_CONTATCS_STATEMENT = " create table "
2014-07-29 12:42:17 +00:00
+ Contact . TABLENAME + " ( " + Contact . ACCOUNT + " TEXT, "
+ Contact . SERVERNAME + " TEXT, " + Contact . SYSTEMNAME + " TEXT, "
+ Contact . JID + " TEXT, " + Contact . KEYS + " TEXT, "
+ Contact . PHOTOURI + " TEXT, " + Contact . OPTIONS + " NUMBER, "
2014-08-24 18:53:13 +00:00
+ Contact . SYSTEMACCOUNT + " NUMBER, " + Contact . AVATAR + " TEXT, "
2015-06-26 13:41:02 +00:00
+ Contact . LAST_PRESENCE + " TEXT, " + Contact . LAST_TIME + " NUMBER, "
2014-11-16 16:21:21 +00:00
+ Contact . GROUPS + " TEXT, FOREIGN KEY( " + Contact . ACCOUNT + " ) REFERENCES "
2014-08-24 18:53:13 +00:00
+ Account . TABLENAME + " ( " + Account . UUID
+ " ) ON DELETE CASCADE, UNIQUE( " + Contact . ACCOUNT + " , "
+ Contact . JID + " ) ON CONFLICT REPLACE); " ;
2014-01-24 22:58:51 +00:00
2016-01-13 02:53:38 +00:00
private static String CREATE_DISCOVERY_RESULTS_STATEMENT = " create table "
+ ServiceDiscoveryResult . TABLENAME + " ( "
+ ServiceDiscoveryResult . HASH + " TEXT, "
+ ServiceDiscoveryResult . VER + " TEXT, "
+ ServiceDiscoveryResult . RESULT + " TEXT, "
+ " UNIQUE( " + ServiceDiscoveryResult . HASH + " , "
+ ServiceDiscoveryResult . VER + " ) ON CONFLICT REPLACE); " ;
2016-04-22 19:25:06 +00:00
private static String CREATE_PRESENCE_TEMPLATES_STATEMENT = " CREATE TABLE "
+ PresenceTemplate . TABELNAME + " ( "
+ PresenceTemplate . UUID + " TEXT, "
+ PresenceTemplate . LAST_USED + " NUMBER, "
+ PresenceTemplate . MESSAGE + " TEXT, "
+ PresenceTemplate . STATUS + " TEXT, "
2018-05-17 18:17:00 +00:00
+ " UNIQUE( " + PresenceTemplate . MESSAGE + " , " + PresenceTemplate . STATUS + " ) ON CONFLICT REPLACE); " ;
2016-04-22 19:25:06 +00:00
2015-05-29 09:17:26 +00:00
private static String CREATE_PREKEYS_STATEMENT = " CREATE TABLE "
2015-07-28 20:00:54 +00:00
+ SQLiteAxolotlStore . PREKEY_TABLENAME + " ( "
2015-11-28 19:11:38 +00:00
+ SQLiteAxolotlStore . ACCOUNT + " TEXT, "
+ SQLiteAxolotlStore . ID + " INTEGER, "
+ SQLiteAxolotlStore . KEY + " TEXT, FOREIGN KEY( "
+ SQLiteAxolotlStore . ACCOUNT
+ " ) REFERENCES " + Account . TABLENAME + " ( " + Account . UUID + " ) ON DELETE CASCADE, "
+ " UNIQUE( " + SQLiteAxolotlStore . ACCOUNT + " , "
+ SQLiteAxolotlStore . ID
+ " ) ON CONFLICT REPLACE "
+ " ); " ;
2015-05-29 09:17:26 +00:00
private static String CREATE_SIGNED_PREKEYS_STATEMENT = " CREATE TABLE "
2015-07-28 20:00:54 +00:00
+ SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME + " ( "
2015-11-28 19:11:38 +00:00
+ SQLiteAxolotlStore . ACCOUNT + " TEXT, "
+ SQLiteAxolotlStore . ID + " INTEGER, "
+ SQLiteAxolotlStore . KEY + " TEXT, FOREIGN KEY( "
+ SQLiteAxolotlStore . ACCOUNT
+ " ) REFERENCES " + Account . TABLENAME + " ( " + Account . UUID + " ) ON DELETE CASCADE, "
+ " UNIQUE( " + SQLiteAxolotlStore . ACCOUNT + " , "
+ SQLiteAxolotlStore . ID
+ " ) ON CONFLICT REPLACE " +
2015-05-29 09:17:26 +00:00
" ); " ;
private static String CREATE_SESSIONS_STATEMENT = " CREATE TABLE "
2015-07-28 20:00:54 +00:00
+ SQLiteAxolotlStore . SESSION_TABLENAME + " ( "
2015-11-28 19:11:38 +00:00
+ SQLiteAxolotlStore . ACCOUNT + " TEXT, "
+ SQLiteAxolotlStore . NAME + " TEXT, "
+ SQLiteAxolotlStore . DEVICE_ID + " INTEGER, "
+ SQLiteAxolotlStore . KEY + " TEXT, FOREIGN KEY( "
+ SQLiteAxolotlStore . ACCOUNT
+ " ) REFERENCES " + Account . TABLENAME + " ( " + Account . UUID + " ) ON DELETE CASCADE, "
+ " UNIQUE( " + SQLiteAxolotlStore . ACCOUNT + " , "
+ SQLiteAxolotlStore . NAME + " , "
+ SQLiteAxolotlStore . DEVICE_ID
+ " ) ON CONFLICT REPLACE "
+ " ); " ;
2015-05-29 09:17:26 +00:00
2015-06-29 11:53:39 +00:00
private static String CREATE_IDENTITIES_STATEMENT = " CREATE TABLE "
2015-07-28 20:00:54 +00:00
+ SQLiteAxolotlStore . IDENTITIES_TABLENAME + " ( "
+ SQLiteAxolotlStore . ACCOUNT + " TEXT, "
+ SQLiteAxolotlStore . NAME + " TEXT, "
+ SQLiteAxolotlStore . OWN + " INTEGER, "
+ SQLiteAxolotlStore . FINGERPRINT + " TEXT, "
2015-12-23 16:41:26 +00:00
+ SQLiteAxolotlStore . CERTIFICATE + " BLOB, "
2016-11-14 21:27:41 +00:00
+ SQLiteAxolotlStore . TRUST + " TEXT, "
+ SQLiteAxolotlStore . ACTIVE + " NUMBER, "
2016-11-19 12:34:54 +00:00
+ SQLiteAxolotlStore . LAST_ACTIVATION + " NUMBER, "
2015-07-28 20:00:54 +00:00
+ SQLiteAxolotlStore . KEY + " TEXT, FOREIGN KEY( "
+ SQLiteAxolotlStore . ACCOUNT
2015-07-10 00:24:33 +00:00
+ " ) REFERENCES " + Account . TABLENAME + " ( " + Account . UUID + " ) ON DELETE CASCADE, "
2015-07-28 20:00:54 +00:00
+ " UNIQUE( " + SQLiteAxolotlStore . ACCOUNT + " , "
2015-11-28 19:11:38 +00:00
+ SQLiteAxolotlStore . NAME + " , "
+ SQLiteAxolotlStore . FINGERPRINT
2015-07-10 00:24:33 +00:00
+ " ) ON CONFLICT IGNORE "
2015-11-28 19:11:38 +00:00
+ " ); " ;
2015-06-29 11:53:39 +00:00
2018-01-21 19:41:30 +00:00
private static String RESOLVER_RESULTS_TABLENAME = " resolver_results " ;
2018-05-17 18:17:00 +00:00
private static String CREATE_RESOLVER_RESULTS_TABLE = " create table " + RESOLVER_RESULTS_TABLENAME + " ( "
2018-01-21 19:41:30 +00:00
+ Resolver . Result . DOMAIN + " TEXT, "
+ Resolver . Result . HOSTNAME + " TEXT, "
+ Resolver . Result . IP + " BLOB, "
+ Resolver . Result . PRIORITY + " NUMBER, "
+ Resolver . Result . DIRECT_TLS + " NUMBER, "
+ Resolver . Result . AUTHENTICATED + " NUMBER, "
+ Resolver . Result . PORT + " NUMBER, "
2018-05-17 18:17:00 +00:00
+ " UNIQUE( " + Resolver . Result . DOMAIN + " ) ON CONFLICT REPLACE "
2018-01-21 19:41:30 +00:00
+ " ); " ;
2016-11-08 11:20:07 +00:00
2018-05-17 18:17:00 +00:00
private static String CREATE_MESSAGE_TIME_INDEX = " create INDEX message_time_index ON " + Message . TABLENAME + " ( " + Message . TIME_SENT + " ) " ;
private static String CREATE_MESSAGE_CONVERSATION_INDEX = " create INDEX message_conversation_index ON " + Message . TABLENAME + " ( " + Message . CONVERSATION + " ) " ;
2017-01-25 12:22:20 +00:00
2018-05-10 09:28:09 +00:00
private static String CREATE_MESSAGE_INDEX_TABLE = " CREATE VIRTUAL TABLE messages_index USING FTS4(uuid TEXT PRIMARY KEY, body TEXT) " ;
2018-05-17 18:17:00 +00:00
private static String CREATE_MESSAGE_INSERT_TRIGGER = " CREATE TRIGGER after_message_insert AFTER INSERT ON " + Message . TABLENAME + " BEGIN INSERT INTO messages_index (uuid,body) VALUES (new.uuid,new.body); END; " ;
private static String CREATE_MESSAGE_UPDATE_TRIGGER = " CREATE TRIGGER after_message_update UPDATE of uuid,body ON " + Message . TABLENAME + " BEGIN update messages_index set body=new.body,uuid=new.uuid WHERE uuid=old.uuid; END; " ;
private static String COPY_PREEXISTING_ENTRIES = " INSERT into messages_index(uuid,body) select uuid,body FROM " + Message . TABLENAME + " ; " ;
2018-04-30 14:06:27 +00:00
2014-09-19 15:21:33 +00:00
private DatabaseBackend ( Context context ) {
2014-01-24 22:58:51 +00:00
super ( context , DATABASE_NAME , null , DATABASE_VERSION ) ;
}
2018-05-17 18:17:00 +00:00
private static ContentValues createFingerprintStatusContentValues ( FingerprintStatus . Trust trust , boolean active ) {
ContentValues values = new ContentValues ( ) ;
values . put ( SQLiteAxolotlStore . TRUST , trust . toString ( ) ) ;
values . put ( SQLiteAxolotlStore . ACTIVE , active ? 1 : 0 ) ;
return values ;
}
public static synchronized DatabaseBackend getInstance ( Context context ) {
if ( instance = = null ) {
instance = new DatabaseBackend ( context ) ;
}
return instance ;
}
2018-05-20 13:54:56 +00:00
@Override
public void onConfigure ( SQLiteDatabase db ) {
db . execSQL ( " PRAGMA foreign_keys=ON " ) ;
2018-05-20 16:01:47 +00:00
db . rawQuery ( " PRAGMA secure_delete=ON " , null ) ;
2018-05-20 13:54:56 +00:00
}
2014-01-24 22:58:51 +00:00
@Override
public void onCreate ( SQLiteDatabase db ) {
2018-05-17 18:17:00 +00:00
db . execSQL ( " create table " + Account . TABLENAME + " ( " + Account . UUID + " TEXT PRIMARY KEY, "
2016-04-25 09:06:17 +00:00
+ Account . USERNAME + " TEXT, "
+ Account . SERVER + " TEXT, "
+ Account . PASSWORD + " TEXT, "
2015-10-29 12:41:08 +00:00
+ Account . DISPLAY_NAME + " TEXT, "
2016-04-25 09:06:17 +00:00
+ Account . STATUS + " TEXT, "
+ Account . STATUS_MESSAGE + " TEXT, "
+ Account . ROSTERVERSION + " TEXT, "
+ Account . OPTIONS + " NUMBER, "
+ Account . AVATAR + " TEXT, "
+ Account . KEYS + " TEXT, "
+ Account . HOSTNAME + " TEXT, "
2018-02-27 19:33:21 +00:00
+ Account . RESOURCE + " TEXT, "
2016-04-25 09:06:17 +00:00
+ Account . PORT + " NUMBER DEFAULT 5222) " ) ;
2014-01-26 02:27:55 +00:00
db . execSQL ( " create table " + Conversation . TABLENAME + " ( "
2014-01-27 19:40:42 +00:00
+ Conversation . UUID + " TEXT PRIMARY KEY, " + Conversation . NAME
2014-02-10 14:24:34 +00:00
+ " TEXT, " + Conversation . CONTACT + " TEXT, "
+ Conversation . ACCOUNT + " TEXT, " + Conversation . CONTACTJID
2014-01-27 19:40:42 +00:00
+ " TEXT, " + Conversation . CREATED + " NUMBER, "
2014-09-27 16:16:31 +00:00
+ Conversation . STATUS + " NUMBER, " + Conversation . MODE
2014-09-28 13:21:56 +00:00
+ " NUMBER, " + Conversation . ATTRIBUTES + " TEXT, FOREIGN KEY( "
+ Conversation . ACCOUNT + " ) REFERENCES " + Account . TABLENAME
+ " ( " + Account . UUID + " ) ON DELETE CASCADE); " ) ;
2014-01-27 19:40:42 +00:00
db . execSQL ( " create table " + Message . TABLENAME + " ( " + Message . UUID
2014-01-28 23:15:38 +00:00
+ " TEXT PRIMARY KEY, " + Message . CONVERSATION + " TEXT, "
+ Message . TIME_SENT + " NUMBER, " + Message . COUNTERPART
2014-07-29 12:42:17 +00:00
+ " TEXT, " + Message . TRUE_COUNTERPART + " TEXT, "
+ Message . BODY + " TEXT, " + Message . ENCRYPTION + " NUMBER, "
2014-08-24 18:53:13 +00:00
+ Message . STATUS + " NUMBER, " + Message . TYPE + " NUMBER, "
2014-11-13 20:04:05 +00:00
+ Message . RELATIVE_FILE_PATH + " TEXT, "
2014-12-09 20:41:49 +00:00
+ Message . SERVER_MSG_ID + " TEXT, "
2015-07-09 12:23:17 +00:00
+ Message . FINGERPRINT + " TEXT, "
2015-07-31 11:08:35 +00:00
+ Message . CARBON + " INTEGER, "
2016-02-15 22:15:04 +00:00
+ Message . EDITED + " TEXT, "
2015-10-14 19:18:34 +00:00
+ Message . READ + " NUMBER DEFAULT 1, "
2016-03-04 19:09:21 +00:00
+ Message . OOB + " INTEGER, "
2016-10-26 10:26:04 +00:00
+ Message . ERROR_MESSAGE + " TEXT, "
2017-11-19 00:53:04 +00:00
+ Message . READ_BY_MARKERS + " TEXT, "
2017-11-25 19:55:43 +00:00
+ Message . MARKABLE + " NUMBER DEFAULT 0, "
2014-08-24 18:53:13 +00:00
+ Message . REMOTE_MSG_ID + " TEXT, FOREIGN KEY( "
+ Message . CONVERSATION + " ) REFERENCES "
+ Conversation . TABLENAME + " ( " + Conversation . UUID
+ " ) ON DELETE CASCADE); " ) ;
2017-01-25 12:22:20 +00:00
db . execSQL ( CREATE_MESSAGE_TIME_INDEX ) ;
2017-02-07 20:17:08 +00:00
db . execSQL ( CREATE_MESSAGE_CONVERSATION_INDEX ) ;
2014-05-19 13:15:09 +00:00
db . execSQL ( CREATE_CONTATCS_STATEMENT ) ;
2016-01-13 02:53:38 +00:00
db . execSQL ( CREATE_DISCOVERY_RESULTS_STATEMENT ) ;
2015-06-29 11:40:56 +00:00
db . execSQL ( CREATE_SESSIONS_STATEMENT ) ;
db . execSQL ( CREATE_PREKEYS_STATEMENT ) ;
db . execSQL ( CREATE_SIGNED_PREKEYS_STATEMENT ) ;
2015-06-29 11:53:39 +00:00
db . execSQL ( CREATE_IDENTITIES_STATEMENT ) ;
2016-04-22 19:25:06 +00:00
db . execSQL ( CREATE_PRESENCE_TEMPLATES_STATEMENT ) ;
2018-01-21 19:41:30 +00:00
db . execSQL ( CREATE_RESOLVER_RESULTS_TABLE ) ;
2018-04-30 15:09:55 +00:00
db . execSQL ( CREATE_MESSAGE_INDEX_TABLE ) ;
db . execSQL ( CREATE_MESSAGE_INSERT_TRIGGER ) ;
db . execSQL ( CREATE_MESSAGE_UPDATE_TRIGGER ) ;
2014-01-24 22:58:51 +00:00
}
@Override
2014-04-03 20:28:37 +00:00
public void onUpgrade ( SQLiteDatabase db , int oldVersion , int newVersion ) {
if ( oldVersion < 2 & & newVersion > = 2 ) {
2014-05-19 13:15:09 +00:00
db . execSQL ( " update " + Account . TABLENAME + " set "
+ Account . OPTIONS + " = " + Account . OPTIONS + " | 8 " ) ;
2014-04-03 20:28:37 +00:00
}
2014-04-06 13:34:08 +00:00
if ( oldVersion < 3 & & newVersion > = 3 ) {
2014-05-19 13:15:09 +00:00
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . TYPE + " NUMBER " ) ;
}
if ( oldVersion < 5 & & newVersion > = 5 ) {
2014-07-29 12:42:17 +00:00
db . execSQL ( " DROP TABLE " + Contact . TABLENAME ) ;
2014-05-19 13:15:09 +00:00
db . execSQL ( CREATE_CONTATCS_STATEMENT ) ;
2014-07-29 12:42:17 +00:00
db . execSQL ( " UPDATE " + Account . TABLENAME + " SET "
+ Account . ROSTERVERSION + " = NULL " ) ;
}
if ( oldVersion < 6 & & newVersion > = 6 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . TRUE_COUNTERPART + " TEXT " ) ;
2014-04-06 13:34:08 +00:00
}
2014-08-21 10:32:50 +00:00
if ( oldVersion < 7 & & newVersion > = 7 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . REMOTE_MSG_ID + " TEXT " ) ;
db . execSQL ( " ALTER TABLE " + Contact . TABLENAME + " ADD COLUMN "
+ Contact . AVATAR + " TEXT " ) ;
db . execSQL ( " ALTER TABLE " + Account . TABLENAME + " ADD COLUMN "
+ Account . AVATAR + " TEXT " ) ;
}
2014-09-27 16:16:31 +00:00
if ( oldVersion < 8 & & newVersion > = 8 ) {
db . execSQL ( " ALTER TABLE " + Conversation . TABLENAME + " ADD COLUMN "
+ Conversation . ATTRIBUTES + " TEXT " ) ;
}
2015-06-26 13:41:02 +00:00
if ( oldVersion < 9 & & newVersion > = 9 ) {
db . execSQL ( " ALTER TABLE " + Contact . TABLENAME + " ADD COLUMN "
+ Contact . LAST_TIME + " NUMBER " ) ;
db . execSQL ( " ALTER TABLE " + Contact . TABLENAME + " ADD COLUMN "
+ Contact . LAST_PRESENCE + " TEXT " ) ;
}
2014-11-13 20:04:05 +00:00
if ( oldVersion < 10 & & newVersion > = 10 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . RELATIVE_FILE_PATH + " TEXT " ) ;
}
2014-11-16 16:21:21 +00:00
if ( oldVersion < 11 & & newVersion > = 11 ) {
db . execSQL ( " ALTER TABLE " + Contact . TABLENAME + " ADD COLUMN "
+ Contact . GROUPS + " TEXT " ) ;
2015-11-28 19:11:38 +00:00
db . execSQL ( " delete from " + Contact . TABLENAME ) ;
db . execSQL ( " update " + Account . TABLENAME + " set " + Account . ROSTERVERSION + " = NULL " ) ;
2014-11-16 16:21:21 +00:00
}
2014-12-09 20:41:49 +00:00
if ( oldVersion < 12 & & newVersion > = 12 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . SERVER_MSG_ID + " TEXT " ) ;
}
2015-01-02 00:21:14 +00:00
if ( oldVersion < 13 & & newVersion > = 13 ) {
2015-11-28 19:11:38 +00:00
db . execSQL ( " delete from " + Contact . TABLENAME ) ;
db . execSQL ( " update " + Account . TABLENAME + " set " + Account . ROSTERVERSION + " = NULL " ) ;
2015-01-02 00:21:14 +00:00
}
2015-05-14 13:25:52 +00:00
if ( oldVersion < 14 & & newVersion > = 14 ) {
2016-09-12 20:48:51 +00:00
canonicalizeJids ( db ) ;
2015-05-14 13:25:52 +00:00
}
2015-11-28 19:11:38 +00:00
if ( oldVersion < 15 & & newVersion > = 15 ) {
2015-07-20 11:15:49 +00:00
recreateAxolotlDb ( db ) ;
2015-07-09 12:23:17 +00:00
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . FINGERPRINT + " TEXT " ) ;
2015-06-25 14:56:34 +00:00
}
2015-07-29 14:41:58 +00:00
if ( oldVersion < 16 & & newVersion > = 16 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . CARBON + " INTEGER " ) ;
}
2015-11-06 13:50:55 +00:00
if ( oldVersion < 19 & & newVersion > = 19 ) {
2015-11-28 19:11:38 +00:00
db . execSQL ( " ALTER TABLE " + Account . TABLENAME + " ADD COLUMN " + Account . DISPLAY_NAME + " TEXT " ) ;
}
if ( oldVersion < 20 & & newVersion > = 20 ) {
db . execSQL ( " ALTER TABLE " + Account . TABLENAME + " ADD COLUMN " + Account . HOSTNAME + " TEXT " ) ;
db . execSQL ( " ALTER TABLE " + Account . TABLENAME + " ADD COLUMN " + Account . PORT + " NUMBER DEFAULT 5222 " ) ;
2015-11-06 13:50:55 +00:00
}
2016-04-22 19:25:06 +00:00
if ( oldVersion < 26 & & newVersion > = 26 ) {
db . execSQL ( " ALTER TABLE " + Account . TABLENAME + " ADD COLUMN " + Account . STATUS + " TEXT " ) ;
db . execSQL ( " ALTER TABLE " + Account . TABLENAME + " ADD COLUMN " + Account . STATUS_MESSAGE + " TEXT " ) ;
}
2018-02-27 19:33:21 +00:00
if ( oldVersion < 40 & & newVersion > = 40 ) {
db . execSQL ( " ALTER TABLE " + Account . TABLENAME + " ADD COLUMN " + Account . RESOURCE + " TEXT " ) ;
}
2015-11-06 13:50:55 +00:00
/ * Any migrations that alter the Account table need to happen BEFORE this migration , as it
* depends on account de - serialization .
* /
2017-07-14 08:34:01 +00:00
if ( oldVersion < 17 & & newVersion > = 17 & & newVersion < 31 ) {
2015-09-05 15:25:46 +00:00
List < Account > accounts = getAccounts ( db ) ;
for ( Account account : accounts ) {
String ownDeviceIdString = account . getKey ( SQLiteAxolotlStore . JSONKEY_REGISTRATION_ID ) ;
2015-11-28 19:11:38 +00:00
if ( ownDeviceIdString = = null ) {
2015-09-05 15:25:46 +00:00
continue ;
}
int ownDeviceId = Integer . valueOf ( ownDeviceIdString ) ;
2018-03-05 17:30:40 +00:00
SignalProtocolAddress ownAddress = new SignalProtocolAddress ( account . getJid ( ) . asBareJid ( ) . toString ( ) , ownDeviceId ) ;
2015-09-05 15:25:46 +00:00
deleteSession ( db , account , ownAddress ) ;
IdentityKeyPair identityKeyPair = loadOwnIdentityKeyPair ( db , account ) ;
2015-09-05 16:47:37 +00:00
if ( identityKeyPair ! = null ) {
2016-11-14 21:27:41 +00:00
String [ ] selectionArgs = {
account . getUuid ( ) ,
2017-06-25 16:18:13 +00:00
CryptoHelper . bytesToHex ( identityKeyPair . getPublicKey ( ) . serialize ( ) )
2016-11-14 21:27:41 +00:00
} ;
ContentValues values = new ContentValues ( ) ;
values . put ( SQLiteAxolotlStore . TRUSTED , 2 ) ;
db . update ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , values ,
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . FINGERPRINT + " = ? " ,
selectionArgs ) ;
2015-09-05 16:47:37 +00:00
} else {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : could not load own identity key pair " ) ;
2015-09-05 16:47:37 +00:00
}
2015-09-05 15:25:46 +00:00
}
}
2015-10-14 19:18:34 +00:00
if ( oldVersion < 18 & & newVersion > = 18 ) {
2015-11-28 19:11:38 +00:00
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN " + Message . READ + " NUMBER DEFAULT 1 " ) ;
2015-10-14 19:18:34 +00:00
}
2015-12-02 15:43:55 +00:00
if ( oldVersion < 21 & & newVersion > = 21 ) {
List < Account > accounts = getAccounts ( db ) ;
for ( Account account : accounts ) {
account . unsetPgpSignature ( ) ;
db . update ( Account . TABLENAME , account . getContentValues ( ) , Account . UUID
+ " =? " , new String [ ] { account . getUuid ( ) } ) ;
}
}
2015-12-23 16:41:26 +00:00
2017-07-13 17:28:16 +00:00
if ( oldVersion > = 15 & & oldVersion < 22 & & newVersion > = 22 ) {
db . execSQL ( " ALTER TABLE " + SQLiteAxolotlStore . IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore . CERTIFICATE ) ;
}
2016-01-13 02:53:38 +00:00
if ( oldVersion < 23 & & newVersion > = 23 ) {
db . execSQL ( CREATE_DISCOVERY_RESULTS_STATEMENT ) ;
}
2016-02-15 22:15:04 +00:00
if ( oldVersion < 24 & & newVersion > = 24 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN " + Message . EDITED + " TEXT " ) ;
}
2016-03-04 19:09:21 +00:00
if ( oldVersion < 25 & & newVersion > = 25 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN " + Message . OOB + " INTEGER " ) ;
}
2016-04-22 19:25:06 +00:00
2018-05-17 18:17:00 +00:00
if ( oldVersion < 26 & & newVersion > = 26 ) {
2016-04-22 19:25:06 +00:00
db . execSQL ( CREATE_PRESENCE_TEMPLATES_STATEMENT ) ;
}
2016-05-19 08:41:56 +00:00
if ( oldVersion < 27 & & newVersion > = 27 ) {
2018-05-17 18:17:00 +00:00
db . execSQL ( " DELETE FROM " + ServiceDiscoveryResult . TABLENAME ) ;
2016-05-19 08:41:56 +00:00
}
2016-09-12 20:48:51 +00:00
if ( oldVersion < 28 & & newVersion > = 28 ) {
canonicalizeJids ( db ) ;
}
2016-10-26 10:26:04 +00:00
if ( oldVersion < 29 & & newVersion > = 29 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN " + Message . ERROR_MESSAGE + " TEXT " ) ;
}
2017-07-13 17:28:16 +00:00
if ( oldVersion > = 15 & & oldVersion < 31 & & newVersion > = 31 ) {
2018-05-17 18:17:00 +00:00
db . execSQL ( " ALTER TABLE " + SQLiteAxolotlStore . IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore . TRUST + " TEXT " ) ;
db . execSQL ( " ALTER TABLE " + SQLiteAxolotlStore . IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore . ACTIVE + " NUMBER " ) ;
HashMap < Integer , ContentValues > migration = new HashMap < > ( ) ;
migration . put ( 0 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . TRUSTED , true ) ) ;
migration . put ( 1 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . TRUSTED , true ) ) ;
migration . put ( 2 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . UNTRUSTED , true ) ) ;
migration . put ( 3 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . COMPROMISED , false ) ) ;
migration . put ( 4 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . TRUSTED , false ) ) ;
migration . put ( 5 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . TRUSTED , false ) ) ;
migration . put ( 6 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . UNTRUSTED , false ) ) ;
migration . put ( 7 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . VERIFIED_X509 , true ) ) ;
migration . put ( 8 , createFingerprintStatusContentValues ( FingerprintStatus . Trust . VERIFIED_X509 , false ) ) ;
for ( Map . Entry < Integer , ContentValues > entry : migration . entrySet ( ) ) {
String whereClause = SQLiteAxolotlStore . TRUSTED + " =? " ;
2016-11-14 21:27:41 +00:00
String [ ] where = { String . valueOf ( entry . getKey ( ) ) } ;
2018-05-17 18:17:00 +00:00
db . update ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , entry . getValue ( ) , whereClause , where ) ;
2016-11-14 21:27:41 +00:00
}
}
2017-07-13 17:28:16 +00:00
if ( oldVersion > = 15 & & oldVersion < 32 & & newVersion > = 32 ) {
2018-05-17 18:17:00 +00:00
db . execSQL ( " ALTER TABLE " + SQLiteAxolotlStore . IDENTITIES_TABLENAME + " ADD COLUMN " + SQLiteAxolotlStore . LAST_ACTIVATION + " NUMBER " ) ;
2016-11-19 12:34:54 +00:00
ContentValues defaults = new ContentValues ( ) ;
2018-05-17 18:17:00 +00:00
defaults . put ( SQLiteAxolotlStore . LAST_ACTIVATION , System . currentTimeMillis ( ) ) ;
db . update ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , defaults , null , null ) ;
2016-11-19 12:34:54 +00:00
}
2017-07-13 17:28:16 +00:00
if ( oldVersion > = 15 & & oldVersion < 33 & & newVersion > = 33 ) {
2018-05-17 18:17:00 +00:00
String whereClause = SQLiteAxolotlStore . OWN + " =1 " ;
db . update ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , createFingerprintStatusContentValues ( FingerprintStatus . Trust . VERIFIED , true ) , whereClause , null ) ;
2016-11-25 16:04:23 +00:00
}
2017-01-25 12:22:20 +00:00
if ( oldVersion < 34 & & newVersion > = 34 ) {
db . execSQL ( CREATE_MESSAGE_TIME_INDEX ) ;
2018-05-17 18:17:00 +00:00
final File oldPicturesDirectory = new File ( Environment . getExternalStoragePublicDirectory ( Environment . DIRECTORY_PICTURES ) + " /Conversations/ " ) ;
2017-01-25 12:22:20 +00:00
final File oldFilesDirectory = new File ( Environment . getExternalStorageDirectory ( ) + " /Conversations/ " ) ;
final File newFilesDirectory = new File ( Environment . getExternalStorageDirectory ( ) + " /Conversations/Media/Conversations Files/ " ) ;
final File newVideosDirectory = new File ( Environment . getExternalStorageDirectory ( ) + " /Conversations/Media/Conversations Videos/ " ) ;
if ( oldPicturesDirectory . exists ( ) & & oldPicturesDirectory . isDirectory ( ) ) {
final File newPicturesDirectory = new File ( Environment . getExternalStorageDirectory ( ) + " /Conversations/Media/Conversations Images/ " ) ;
newPicturesDirectory . getParentFile ( ) . mkdirs ( ) ;
if ( oldPicturesDirectory . renameTo ( newPicturesDirectory ) ) {
2018-05-17 18:17:00 +00:00
Log . d ( Config . LOGTAG , " moved " + oldPicturesDirectory . getAbsolutePath ( ) + " to " + newPicturesDirectory . getAbsolutePath ( ) ) ;
2017-01-25 12:22:20 +00:00
}
}
if ( oldFilesDirectory . exists ( ) & & oldFilesDirectory . isDirectory ( ) ) {
newFilesDirectory . mkdirs ( ) ;
newVideosDirectory . mkdirs ( ) ;
2017-02-07 09:20:13 +00:00
final File [ ] files = oldFilesDirectory . listFiles ( ) ;
if ( files = = null ) {
return ;
}
2018-05-17 18:17:00 +00:00
for ( File file : files ) {
2017-01-25 12:22:20 +00:00
if ( file . getName ( ) . equals ( " .nomedia " ) ) {
if ( file . delete ( ) ) {
2018-05-17 18:17:00 +00:00
Log . d ( Config . LOGTAG , " deleted nomedia file in " + oldFilesDirectory . getAbsolutePath ( ) ) ;
2017-01-25 12:22:20 +00:00
}
} else if ( file . isFile ( ) ) {
final String name = file . getName ( ) ;
boolean isVideo = false ;
int start = name . lastIndexOf ( '.' ) + 1 ;
if ( start < name . length ( ) ) {
2018-05-17 18:17:00 +00:00
String mime = MimeUtils . guessMimeTypeFromExtension ( name . substring ( start ) ) ;
2017-01-25 12:22:20 +00:00
isVideo = mime ! = null & & mime . startsWith ( " video/ " ) ;
}
2018-05-17 18:17:00 +00:00
File dst = new File ( ( isVideo ? newVideosDirectory : newFilesDirectory ) . getAbsolutePath ( ) + " / " + file . getName ( ) ) ;
2017-01-25 12:22:20 +00:00
if ( file . renameTo ( dst ) ) {
Log . d ( Config . LOGTAG , " moved " + file + " to " + dst ) ;
}
}
}
}
}
2017-02-07 20:17:08 +00:00
if ( oldVersion < 35 & & newVersion > = 35 ) {
db . execSQL ( CREATE_MESSAGE_CONVERSATION_INDEX ) ;
}
2017-07-12 20:16:31 +00:00
if ( oldVersion < 36 & & newVersion > = 36 ) {
List < Account > accounts = getAccounts ( db ) ;
for ( Account account : accounts ) {
2018-05-17 18:17:00 +00:00
account . setOption ( Account . OPTION_REQUIRES_ACCESS_MODE_CHANGE , true ) ;
account . setOption ( Account . OPTION_LOGGED_IN_SUCCESSFULLY , false ) ;
2017-07-12 20:16:31 +00:00
db . update ( Account . TABLENAME , account . getContentValues ( ) , Account . UUID
+ " =? " , new String [ ] { account . getUuid ( ) } ) ;
}
}
2017-11-19 00:53:04 +00:00
if ( oldVersion < 37 & & newVersion > = 37 ) {
2017-11-25 19:55:43 +00:00
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN " + Message . READ_BY_MARKERS + " TEXT " ) ;
}
if ( oldVersion < 38 & & newVersion > = 38 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN " + Message . MARKABLE + " NUMBER DEFAULT 0 " ) ;
2017-11-19 00:53:04 +00:00
}
2018-01-21 19:41:30 +00:00
if ( oldVersion < 39 & & newVersion > = 39 ) {
db . execSQL ( CREATE_RESOLVER_RESULTS_TABLE ) ;
}
2018-04-30 14:06:27 +00:00
if ( oldVersion < 41 & & newVersion > = 41 ) {
db . execSQL ( CREATE_MESSAGE_INDEX_TABLE ) ;
db . execSQL ( CREATE_MESSAGE_INSERT_TRIGGER ) ;
db . execSQL ( CREATE_MESSAGE_UPDATE_TRIGGER ) ;
db . execSQL ( COPY_PREEXISTING_ENTRIES ) ;
}
2016-11-14 21:27:41 +00:00
2018-05-17 18:17:00 +00:00
if ( oldVersion < 42 & & newVersion > = 42 ) {
db . execSQL ( " DROP TRIGGER IF EXISTS after_message_delete " ) ;
}
2018-11-25 19:47:50 +00:00
if ( QuickConversationsService . isQuicksy ( ) & & oldVersion < 43 & & newVersion > = 43 ) {
List < Account > accounts = getAccounts ( db ) ;
for ( Account account : accounts ) {
account . setOption ( Account . OPTION_MAGIC_CREATE , true ) ;
db . update ( Account . TABLENAME , account . getContentValues ( ) , Account . UUID
+ " =? " , new String [ ] { account . getUuid ( ) } ) ;
}
}
2016-09-12 20:48:51 +00:00
}
private void canonicalizeJids ( SQLiteDatabase db ) {
// migrate db to new, canonicalized JID domainpart representation
// Conversation table
Cursor cursor = db . rawQuery ( " select * from " + Conversation . TABLENAME , new String [ 0 ] ) ;
while ( cursor . moveToNext ( ) ) {
String newJid ;
try {
2018-03-05 17:30:40 +00:00
newJid = Jid . of ( cursor . getString ( cursor . getColumnIndex ( Conversation . CONTACTJID ) ) ) . toString ( ) ;
} catch ( IllegalArgumentException ignored ) {
2016-09-12 20:48:51 +00:00
Log . e ( Config . LOGTAG , " Failed to migrate Conversation CONTACTJID "
+ cursor . getString ( cursor . getColumnIndex ( Conversation . CONTACTJID ) )
+ " : " + ignored + " . Skipping... " ) ;
continue ;
}
String updateArgs [ ] = {
newJid ,
cursor . getString ( cursor . getColumnIndex ( Conversation . UUID ) ) ,
} ;
db . execSQL ( " update " + Conversation . TABLENAME
+ " set " + Conversation . CONTACTJID + " = ? "
+ " where " + Conversation . UUID + " = ? " , updateArgs ) ;
}
cursor . close ( ) ;
// Contact table
cursor = db . rawQuery ( " select * from " + Contact . TABLENAME , new String [ 0 ] ) ;
while ( cursor . moveToNext ( ) ) {
String newJid ;
try {
2018-03-05 17:30:40 +00:00
newJid = Jid . of ( cursor . getString ( cursor . getColumnIndex ( Contact . JID ) ) ) . toString ( ) ;
} catch ( IllegalArgumentException ignored ) {
2016-09-12 20:48:51 +00:00
Log . e ( Config . LOGTAG , " Failed to migrate Contact JID "
+ cursor . getString ( cursor . getColumnIndex ( Contact . JID ) )
+ " : " + ignored + " . Skipping... " ) ;
continue ;
}
String updateArgs [ ] = {
newJid ,
cursor . getString ( cursor . getColumnIndex ( Contact . ACCOUNT ) ) ,
cursor . getString ( cursor . getColumnIndex ( Contact . JID ) ) ,
} ;
db . execSQL ( " update " + Contact . TABLENAME
+ " set " + Contact . JID + " = ? "
+ " where " + Contact . ACCOUNT + " = ? "
+ " AND " + Contact . JID + " = ? " , updateArgs ) ;
}
cursor . close ( ) ;
// Account table
cursor = db . rawQuery ( " select * from " + Account . TABLENAME , new String [ 0 ] ) ;
while ( cursor . moveToNext ( ) ) {
String newServer ;
try {
2018-03-05 17:30:40 +00:00
newServer = Jid . of (
2016-09-12 20:48:51 +00:00
cursor . getString ( cursor . getColumnIndex ( Account . USERNAME ) ) ,
cursor . getString ( cursor . getColumnIndex ( Account . SERVER ) ) ,
2018-03-05 17:30:40 +00:00
null
) . getDomain ( ) ;
} catch ( IllegalArgumentException ignored ) {
2016-09-12 20:48:51 +00:00
Log . e ( Config . LOGTAG , " Failed to migrate Account SERVER "
+ cursor . getString ( cursor . getColumnIndex ( Account . SERVER ) )
+ " : " + ignored + " . Skipping... " ) ;
continue ;
}
String updateArgs [ ] = {
newServer ,
cursor . getString ( cursor . getColumnIndex ( Account . UUID ) ) ,
} ;
db . execSQL ( " update " + Account . TABLENAME
+ " set " + Account . SERVER + " = ? "
+ " where " + Account . UUID + " = ? " , updateArgs ) ;
}
cursor . close ( ) ;
2014-01-24 22:58:51 +00:00
}
2014-01-26 02:27:55 +00:00
2014-01-27 19:40:42 +00:00
public void createConversation ( Conversation conversation ) {
2014-01-24 22:58:51 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2014-01-27 19:40:42 +00:00
db . insert ( Conversation . TABLENAME , null , conversation . getContentValues ( ) ) ;
}
public void createMessage ( Message message ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
db . insert ( Message . TABLENAME , null , message . getContentValues ( ) ) ;
2014-01-24 22:58:51 +00:00
}
2014-01-28 23:15:38 +00:00
2014-01-28 18:21:54 +00:00
public void createAccount ( Account account ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2014-01-28 23:15:38 +00:00
db . insert ( Account . TABLENAME , null , account . getContentValues ( ) ) ;
2014-01-28 18:21:54 +00:00
}
2014-05-19 13:15:09 +00:00
2016-01-13 02:53:38 +00:00
public void insertDiscoveryResult ( ServiceDiscoveryResult result ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
db . insert ( ServiceDiscoveryResult . TABLENAME , null , result . getContentValues ( ) ) ;
}
public ServiceDiscoveryResult findDiscoveryResult ( final String hash , final String ver ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
String [ ] selectionArgs = { hash , ver } ;
Cursor cursor = db . query ( ServiceDiscoveryResult . TABLENAME , null ,
ServiceDiscoveryResult . HASH + " =? AND " + ServiceDiscoveryResult . VER + " =? " ,
selectionArgs , null , null , null ) ;
2016-03-11 08:01:27 +00:00
if ( cursor . getCount ( ) = = 0 ) {
cursor . close ( ) ;
2016-01-13 02:53:38 +00:00
return null ;
2016-03-11 08:01:27 +00:00
}
2016-01-13 02:53:38 +00:00
cursor . moveToFirst ( ) ;
ServiceDiscoveryResult result = null ;
try {
result = new ServiceDiscoveryResult ( cursor ) ;
} catch ( JSONException e ) { /* result is still null */ }
cursor . close ( ) ;
return result ;
}
2018-01-21 19:41:30 +00:00
public void saveResolverResult ( String domain , Resolver . Result result ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
ContentValues contentValues = result . toContentValues ( ) ;
2018-05-17 18:17:00 +00:00
contentValues . put ( Resolver . Result . DOMAIN , domain ) ;
2018-01-21 19:41:30 +00:00
db . insert ( RESOLVER_RESULTS_TABLENAME , null , contentValues ) ;
}
2018-11-13 08:58:28 +00:00
public synchronized Resolver . Result findResolverResult ( String domain ) {
2018-01-21 19:41:30 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2018-05-17 18:17:00 +00:00
String where = Resolver . Result . DOMAIN + " =? " ;
2018-01-21 19:41:30 +00:00
String [ ] whereArgs = { domain } ;
2018-10-07 11:44:20 +00:00
final Cursor cursor = db . query ( RESOLVER_RESULTS_TABLENAME , null , where , whereArgs , null , null , null ) ;
2018-01-21 19:41:30 +00:00
Resolver . Result result = null ;
if ( cursor ! = null ) {
2018-11-13 08:58:28 +00:00
try {
if ( cursor . moveToFirst ( ) ) {
result = Resolver . Result . fromCursor ( cursor ) ;
}
} catch ( Exception e ) {
Log . d ( Config . LOGTAG , " unable to find cached resolver result in database " + e . getMessage ( ) ) ;
return null ;
} finally {
cursor . close ( ) ;
2018-01-21 19:41:30 +00:00
}
}
return result ;
}
2016-04-22 19:25:06 +00:00
public void insertPresenceTemplate ( PresenceTemplate template ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2018-05-17 18:17:00 +00:00
String whereToDelete = PresenceTemplate . MESSAGE + " =? " ;
2018-03-04 10:43:58 +00:00
String [ ] whereToDeleteArgs = { template . getStatusMessage ( ) } ;
2018-05-17 18:17:00 +00:00
db . delete ( PresenceTemplate . TABELNAME , whereToDelete , whereToDeleteArgs ) ;
db . delete ( PresenceTemplate . TABELNAME , PresenceTemplate . UUID + " not in (select " + PresenceTemplate . UUID + " from " + PresenceTemplate . TABELNAME + " order by " + PresenceTemplate . LAST_USED + " desc limit 9) " , null ) ;
2016-04-22 19:25:06 +00:00
db . insert ( PresenceTemplate . TABELNAME , null , template . getContentValues ( ) ) ;
}
public List < PresenceTemplate > getPresenceTemplates ( ) {
ArrayList < PresenceTemplate > templates = new ArrayList < > ( ) ;
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2018-05-17 18:17:00 +00:00
Cursor cursor = db . query ( PresenceTemplate . TABELNAME , null , null , null , null , null , PresenceTemplate . LAST_USED + " desc " ) ;
2016-04-22 19:25:06 +00:00
while ( cursor . moveToNext ( ) ) {
templates . add ( PresenceTemplate . fromCursor ( cursor ) ) ;
}
cursor . close ( ) ;
return templates ;
}
2014-07-12 10:41:37 +00:00
public CopyOnWriteArrayList < Conversation > getConversations ( int status ) {
2014-11-05 20:55:47 +00:00
CopyOnWriteArrayList < Conversation > list = new CopyOnWriteArrayList < > ( ) ;
2014-01-24 22:58:51 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-11-28 19:11:38 +00:00
String [ ] selectionArgs = { Integer . toString ( status ) } ;
2014-01-27 19:40:42 +00:00
Cursor cursor = db . rawQuery ( " select * from " + Conversation . TABLENAME
2018-05-17 18:17:00 +00:00
+ " where " + Conversation . STATUS + " = ? and " + Conversation . CONTACTJID + " is not null order by "
2014-01-27 19:40:42 +00:00
+ Conversation . CREATED + " desc " , selectionArgs ) ;
2014-01-26 02:27:55 +00:00
while ( cursor . moveToNext ( ) ) {
2018-05-09 09:09:01 +00:00
final Conversation conversation = Conversation . fromCursor ( cursor ) ;
if ( conversation . getJid ( ) instanceof InvalidJid ) {
continue ;
}
list . add ( conversation ) ;
2014-01-24 22:58:51 +00:00
}
2014-11-15 23:34:16 +00:00
cursor . close ( ) ;
2014-01-24 22:58:51 +00:00
return list ;
}
2014-07-29 12:42:17 +00:00
2014-10-20 19:08:33 +00:00
public ArrayList < Message > getMessages ( Conversation conversations , int limit ) {
2014-07-29 12:42:17 +00:00
return getMessages ( conversations , limit , - 1 ) ;
2014-06-14 14:59:07 +00:00
}
2014-01-24 22:58:51 +00:00
2018-04-26 11:22:31 +00:00
public ArrayList < Message > getMessages ( Conversation conversation , int limit , long timestamp ) {
2014-11-05 20:55:47 +00:00
ArrayList < Message > list = new ArrayList < > ( ) ;
2014-01-27 19:40:42 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2014-06-14 14:59:07 +00:00
Cursor cursor ;
2014-07-29 12:42:17 +00:00
if ( timestamp = = - 1 ) {
2015-11-28 19:11:38 +00:00
String [ ] selectionArgs = { conversation . getUuid ( ) } ;
2014-06-14 14:59:07 +00:00
cursor = db . query ( Message . TABLENAME , null , Message . CONVERSATION
2014-07-29 12:42:17 +00:00
+ " =? " , selectionArgs , null , null , Message . TIME_SENT
+ " DESC " , String . valueOf ( limit ) ) ;
2014-06-14 14:59:07 +00:00
} else {
2015-11-28 19:11:38 +00:00
String [ ] selectionArgs = { conversation . getUuid ( ) ,
Long . toString ( timestamp ) } ;
2014-06-14 14:59:07 +00:00
cursor = db . query ( Message . TABLENAME , null , Message . CONVERSATION
2015-11-28 19:11:38 +00:00
+ " =? and " + Message . TIME_SENT + " <? " , selectionArgs ,
2014-07-29 12:42:17 +00:00
null , null , Message . TIME_SENT + " DESC " ,
2014-06-14 14:59:07 +00:00
String . valueOf ( limit ) ) ;
}
2014-01-28 23:15:38 +00:00
if ( cursor . getCount ( ) > 0 ) {
2014-01-27 19:40:42 +00:00
cursor . moveToLast ( ) ;
do {
2018-05-17 18:17:00 +00:00
Message message = Message . fromCursor ( cursor , conversation ) ;
2017-01-30 05:03:51 +00:00
if ( message ! = null ) {
list . add ( message ) ;
}
2014-01-27 19:40:42 +00:00
} while ( cursor . moveToPrevious ( ) ) ;
}
2014-11-15 23:34:16 +00:00
cursor . close ( ) ;
2014-01-27 19:40:42 +00:00
return list ;
}
2018-04-30 15:09:55 +00:00
public Cursor getMessageSearchCursor ( List < String > term ) {
2018-04-26 11:22:31 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2018-05-17 18:17:00 +00:00
String SQL = " SELECT " + Message . TABLENAME + " .*, " + Conversation . TABLENAME + '.' + Conversation . CONTACTJID + ',' + Conversation . TABLENAME + '.' + Conversation . ACCOUNT + ',' + Conversation . TABLENAME + '.' + Conversation . MODE + " FROM " + Message . TABLENAME + " join " + Conversation . TABLENAME + " on " + Message . TABLENAME + '.' + Message . CONVERSATION + '=' + Conversation . TABLENAME + '.' + Conversation . UUID + " join messages_index ON messages_index.uuid=messages.uuid where " + Message . ENCRYPTION + " NOT IN( " + Message . ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + ',' + Message . ENCRYPTION_PGP + ',' + Message . ENCRYPTION_DECRYPTION_FAILED + " ) AND " + Message . TYPE + " IN( " + Message . TYPE_TEXT + ',' + Message . TYPE_PRIVATE + " ) AND messages_index.body MATCH ? ORDER BY " + Message . TIME_SENT + " DESC limit " + Config . MAX_SEARCH_RESULTS ;
Log . d ( Config . LOGTAG , " search term: " + FtsUtils . toMatchString ( term ) ) ;
return db . rawQuery ( SQL , new String [ ] { FtsUtils . toMatchString ( term ) } ) ;
2018-04-26 11:22:31 +00:00
}
2015-11-28 19:11:38 +00:00
public Iterable < Message > getMessagesIterable ( final Conversation conversation ) {
2018-04-26 11:22:31 +00:00
return ( ) - > {
class MessageIterator implements Iterator < Message > {
private SQLiteDatabase db = getReadableDatabase ( ) ;
private String [ ] selectionArgs = { conversation . getUuid ( ) } ;
private Cursor cursor = db . query ( Message . TABLENAME , null , Message . CONVERSATION
+ " =? " , selectionArgs , null , null , Message . TIME_SENT
+ " ASC " , null ) ;
private MessageIterator ( ) {
cursor . moveToFirst ( ) ;
}
2015-09-20 21:17:32 +00:00
2018-04-26 11:22:31 +00:00
@Override
public boolean hasNext ( ) {
return ! cursor . isAfterLast ( ) ;
}
2015-09-20 21:17:32 +00:00
2018-04-26 11:22:31 +00:00
@Override
public Message next ( ) {
Message message = Message . fromCursor ( cursor , conversation ) ;
cursor . moveToNext ( ) ;
return message ;
}
2015-09-20 21:17:32 +00:00
2018-04-26 11:22:31 +00:00
@Override
public void remove ( ) {
throw new UnsupportedOperationException ( ) ;
2015-09-20 21:17:32 +00:00
}
}
2018-04-26 11:22:31 +00:00
return new MessageIterator ( ) ;
2015-09-20 21:17:32 +00:00
} ;
}
2018-09-15 19:10:17 +00:00
public List < FilePath > getRelativeFilePaths ( String account , Jid jid , int limit ) {
2018-09-15 17:38:45 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
final String SQL = " select uuid,relativeFilePath from messages where type in (1,2) and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc " ;
2018-09-15 19:10:17 +00:00
final String [ ] args = { account , jid . toEscapedString ( ) , jid . toEscapedString ( ) + " /% " } ;
2018-09-15 17:38:45 +00:00
Cursor cursor = db . rawQuery ( SQL + ( limit > 0 ? " limit " + String . valueOf ( limit ) : " " ) , args ) ;
List < FilePath > filesPaths = new ArrayList < > ( ) ;
while ( cursor . moveToNext ( ) ) {
filesPaths . add ( new FilePath ( cursor . getString ( 0 ) , cursor . getString ( 1 ) ) ) ;
}
cursor . close ( ) ;
return filesPaths ;
}
public static class FilePath {
public final UUID uuid ;
public final String path ;
private FilePath ( String uuid , String path ) {
this . uuid = UUID . fromString ( uuid ) ;
this . path = path ;
}
}
2014-11-05 20:55:47 +00:00
public Conversation findConversation ( final Account account , final Jid contactJid ) {
2014-01-27 19:40:42 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-11-28 19:11:38 +00:00
String [ ] selectionArgs = { account . getUuid ( ) ,
2018-03-05 17:30:40 +00:00
contactJid . asBareJid ( ) . toString ( ) + " /% " ,
contactJid . asBareJid ( ) . toString ( )
2015-11-28 19:11:38 +00:00
} ;
2014-01-28 23:15:38 +00:00
Cursor cursor = db . query ( Conversation . TABLENAME , null ,
2015-01-21 15:18:57 +00:00
Conversation . ACCOUNT + " =? AND ( " + Conversation . CONTACTJID
2015-05-29 09:17:26 +00:00
+ " like ? OR " + Conversation . CONTACTJID + " =?) " , selectionArgs , null , null , null ) ;
2016-03-31 11:55:46 +00:00
if ( cursor . getCount ( ) = = 0 ) {
cursor . close ( ) ;
2014-01-28 23:15:38 +00:00
return null ;
2016-03-31 11:55:46 +00:00
}
2014-01-27 19:40:42 +00:00
cursor . moveToFirst ( ) ;
2014-11-15 23:34:16 +00:00
Conversation conversation = Conversation . fromCursor ( cursor ) ;
cursor . close ( ) ;
2018-05-09 09:09:01 +00:00
if ( conversation . getJid ( ) instanceof InvalidJid ) {
return null ;
}
2014-11-15 23:34:16 +00:00
return conversation ;
2014-01-27 19:40:42 +00:00
}
2014-12-21 20:43:58 +00:00
public void updateConversation ( final Conversation conversation ) {
final SQLiteDatabase db = this . getWritableDatabase ( ) ;
2015-11-28 19:11:38 +00:00
final String [ ] args = { conversation . getUuid ( ) } ;
2014-01-28 23:15:38 +00:00
db . update ( Conversation . TABLENAME , conversation . getContentValues ( ) ,
Conversation . UUID + " =? " , args ) ;
2014-01-27 19:40:42 +00:00
}
2014-01-28 23:15:38 +00:00
2014-01-28 18:21:54 +00:00
public List < Account > getAccounts ( ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-09-05 15:25:46 +00:00
return getAccounts ( db ) ;
}
2017-12-15 17:25:21 +00:00
public List < Jid > getAccountJids ( ) {
2017-12-11 14:56:15 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
final List < Jid > jids = new ArrayList < > ( ) ;
final String [ ] columns = new String [ ] { Account . USERNAME , Account . SERVER } ;
2018-03-13 10:54:34 +00:00
String where = " not options & (1 <<1) " ;
2018-05-17 18:17:00 +00:00
Cursor cursor = db . query ( Account . TABLENAME , columns , where , null , null , null , null ) ;
2017-12-11 14:56:15 +00:00
try {
2018-05-17 18:17:00 +00:00
while ( cursor . moveToNext ( ) ) {
jids . add ( Jid . of ( cursor . getString ( 0 ) , cursor . getString ( 1 ) , null ) ) ;
2017-12-11 14:56:15 +00:00
}
return jids ;
} catch ( Exception e ) {
return jids ;
} finally {
if ( cursor ! = null ) {
cursor . close ( ) ;
}
}
}
2015-09-05 15:25:46 +00:00
private List < Account > getAccounts ( SQLiteDatabase db ) {
List < Account > list = new ArrayList < > ( ) ;
2014-01-28 23:15:38 +00:00
Cursor cursor = db . query ( Account . TABLENAME , null , null , null , null ,
null , null ) ;
2014-01-28 18:21:54 +00:00
while ( cursor . moveToNext ( ) ) {
list . add ( Account . fromCursor ( cursor ) ) ;
}
2014-10-08 12:10:37 +00:00
cursor . close ( ) ;
2014-01-28 18:21:54 +00:00
return list ;
}
2016-09-07 12:34:58 +00:00
public boolean updateAccount ( Account account ) {
2014-01-28 18:21:54 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2015-11-28 19:11:38 +00:00
String [ ] args = { account . getUuid ( ) } ;
2016-09-07 12:34:58 +00:00
final int rows = db . update ( Account . TABLENAME , account . getContentValues ( ) , Account . UUID + " =? " , args ) ;
return rows = = 1 ;
2014-01-28 18:21:54 +00:00
}
2016-09-07 12:34:58 +00:00
public boolean deleteAccount ( Account account ) {
2014-01-28 18:21:54 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2015-11-28 19:11:38 +00:00
String [ ] args = { account . getUuid ( ) } ;
2016-09-07 12:34:58 +00:00
final int rows = db . delete ( Account . TABLENAME , Account . UUID + " =? " , args ) ;
return rows = = 1 ;
2014-01-28 18:21:54 +00:00
}
2014-09-28 13:21:56 +00:00
2018-05-10 08:47:28 +00:00
public boolean updateMessage ( Message message , boolean includeBody ) {
2014-02-02 15:05:15 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2015-11-28 19:11:38 +00:00
String [ ] args = { message . getUuid ( ) } ;
2018-05-10 08:47:28 +00:00
ContentValues contentValues = message . getContentValues ( ) ;
contentValues . remove ( Message . UUID ) ;
if ( ! includeBody ) {
contentValues . remove ( Message . BODY ) ;
}
2018-04-21 17:35:25 +00:00
return db . update ( Message . TABLENAME , message . getContentValues ( ) , Message . UUID + " =? " , args ) = = 1 ;
2014-02-02 15:05:15 +00:00
}
2014-02-05 21:33:39 +00:00
2018-12-01 14:52:44 +00:00
public boolean updateMessage ( Message message , String uuid ) {
2016-02-15 22:15:04 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { uuid } ;
2018-12-01 14:52:44 +00:00
return db . update ( Message . TABLENAME , message . getContentValues ( ) , Message . UUID + " =? " , args ) = = 1 ;
2016-02-15 22:15:04 +00:00
}
2014-05-19 13:15:09 +00:00
public void readRoster ( Roster roster ) {
2014-02-05 21:33:39 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2014-02-10 02:34:00 +00:00
Cursor cursor ;
2015-11-28 19:11:38 +00:00
String args [ ] = { roster . getAccount ( ) . getUuid ( ) } ;
2015-07-03 19:32:46 +00:00
cursor = db . query ( Contact . TABLENAME , null , Contact . ACCOUNT + " =? " , args , null , null , null ) ;
2014-02-05 21:33:39 +00:00
while ( cursor . moveToNext ( ) ) {
2014-05-19 13:15:09 +00:00
roster . initContact ( Contact . fromCursor ( cursor ) ) ;
2014-02-05 21:33:39 +00:00
}
2014-10-08 12:10:37 +00:00
cursor . close ( ) ;
2014-02-05 21:33:39 +00:00
}
2014-07-29 12:42:17 +00:00
2014-11-05 20:55:47 +00:00
public void writeRoster ( final Roster roster ) {
2018-03-18 11:24:28 +00:00
long start = SystemClock . elapsedRealtime ( ) ;
2014-11-05 20:55:47 +00:00
final Account account = roster . getAccount ( ) ;
final SQLiteDatabase db = this . getWritableDatabase ( ) ;
2016-01-13 07:55:46 +00:00
db . beginTransaction ( ) ;
2014-07-29 12:42:17 +00:00
for ( Contact contact : roster . getContacts ( ) ) {
2018-10-28 21:35:31 +00:00
if ( contact . getOption ( Contact . Options . IN_ROSTER ) | | contact . getAvatarFilename ( ) ! = null | | contact . getOption ( Contact . Options . SYNCED_VIA_OTHER ) ) {
2014-05-19 19:05:17 +00:00
db . insert ( Contact . TABLENAME , null , contact . getContentValues ( ) ) ;
} else {
2014-07-29 12:42:17 +00:00
String where = Contact . ACCOUNT + " =? AND " + Contact . JID + " =? " ;
2018-03-05 17:30:40 +00:00
String [ ] whereArgs = { account . getUuid ( ) , contact . getJid ( ) . toString ( ) } ;
2014-05-19 19:05:17 +00:00
db . delete ( Contact . TABLENAME , where , whereArgs ) ;
}
}
2016-01-13 07:55:46 +00:00
db . setTransactionSuccessful ( ) ;
db . endTransaction ( ) ;
2014-05-19 19:05:17 +00:00
account . setRosterVersion ( roster . getVersion ( ) ) ;
updateAccount ( account ) ;
2018-03-18 11:24:28 +00:00
long duration = SystemClock . elapsedRealtime ( ) - start ;
2018-05-17 18:17:00 +00:00
Log . d ( Config . LOGTAG , account . getJid ( ) . asBareJid ( ) + " : persisted roster in " + duration + " ms " ) ;
2014-02-05 21:33:39 +00:00
}
2014-02-11 22:55:03 +00:00
2014-04-20 18:48:16 +00:00
public void deleteMessagesInConversation ( Conversation conversation ) {
2018-05-10 09:28:09 +00:00
long start = SystemClock . elapsedRealtime ( ) ;
2018-04-25 17:32:43 +00:00
final SQLiteDatabase db = this . getWritableDatabase ( ) ;
2018-05-17 18:17:00 +00:00
db . beginTransaction ( ) ;
2015-11-28 19:11:38 +00:00
String [ ] args = { conversation . getUuid ( ) } ;
2018-05-17 18:17:00 +00:00
db . delete ( " messages_index " , " uuid in (select uuid from messages where conversationUuid=?) " , args ) ;
2018-04-25 17:32:43 +00:00
int num = db . delete ( Message . TABLENAME , Message . CONVERSATION + " =? " , args ) ;
2018-05-17 18:17:00 +00:00
db . setTransactionSuccessful ( ) ;
db . endTransaction ( ) ;
Log . d ( Config . LOGTAG , " deleted " + num + " messages for " + conversation . getJid ( ) . asBareJid ( ) + " in " + ( SystemClock . elapsedRealtime ( ) - start ) + " ms " ) ;
2014-04-20 18:48:16 +00:00
}
2014-02-19 00:35:23 +00:00
2018-05-17 18:17:00 +00:00
public void expireOldMessages ( long timestamp ) {
final String [ ] args = { String . valueOf ( timestamp ) } ;
2017-01-23 16:14:30 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2018-05-17 18:17:00 +00:00
db . beginTransaction ( ) ;
db . delete ( " messages_index " , " uuid in (select uuid from messages where timeSent<?) " , args ) ;
db . delete ( Message . TABLENAME , " timeSent<? " , args ) ;
db . setTransactionSuccessful ( ) ;
db . endTransaction ( ) ;
2017-01-23 16:14:30 +00:00
}
2017-05-07 19:05:35 +00:00
public MamReference getLastMessageReceived ( Account account ) {
2016-03-31 11:55:46 +00:00
Cursor cursor = null ;
2016-01-15 22:46:52 +00:00
try {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2018-04-21 14:57:29 +00:00
String sql = " select messages.timeSent,messages.serverMsgId from accounts join conversations on accounts.uuid=conversations.accountUuid join messages on conversations.uuid=messages.conversationUuid where accounts.uuid=? and (messages.status=0 or messages.carbon=1 or messages.serverMsgId not null) and (conversations.mode=0 or (messages.serverMsgId not null and messages.type=4)) order by messages.timesent desc limit 1 " ;
2016-01-15 22:46:52 +00:00
String [ ] args = { account . getUuid ( ) } ;
2016-03-31 11:55:46 +00:00
cursor = db . rawQuery ( sql , args ) ;
2016-01-15 22:46:52 +00:00
if ( cursor . getCount ( ) = = 0 ) {
return null ;
} else {
cursor . moveToFirst ( ) ;
2017-05-07 19:05:35 +00:00
return new MamReference ( cursor . getLong ( 0 ) , cursor . getString ( 1 ) ) ;
2016-01-15 22:46:52 +00:00
}
} catch ( Exception e ) {
2015-12-11 12:52:04 +00:00
return null ;
2016-03-31 11:55:46 +00:00
} finally {
if ( cursor ! = null ) {
cursor . close ( ) ;
}
2015-12-11 12:52:04 +00:00
}
}
2016-11-19 20:39:16 +00:00
public long getLastTimeFingerprintUsed ( Account account , String fingerprint ) {
String SQL = " select messages.timeSent from accounts join conversations on accounts.uuid=conversations.accountUuid join messages on conversations.uuid=messages.conversationUuid where accounts.uuid=? and messages.axolotl_fingerprint=? order by messages.timesent desc limit 1 " ;
String [ ] args = { account . getUuid ( ) , fingerprint } ;
2018-05-17 18:17:00 +00:00
Cursor cursor = getReadableDatabase ( ) . rawQuery ( SQL , args ) ;
2016-11-19 20:39:16 +00:00
long time ;
if ( cursor . moveToFirst ( ) ) {
time = cursor . getLong ( 0 ) ;
} else {
time = 0 ;
}
cursor . close ( ) ;
return time ;
}
2017-05-07 19:05:35 +00:00
public MamReference getLastClearDate ( Account account ) {
2016-09-16 09:07:52 +00:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
String [ ] columns = { Conversation . ATTRIBUTES } ;
String selection = Conversation . ACCOUNT + " =? " ;
String [ ] args = { account . getUuid ( ) } ;
2018-05-17 18:17:00 +00:00
Cursor cursor = db . query ( Conversation . TABLENAME , columns , selection , args , null , null , null ) ;
2017-05-07 19:05:35 +00:00
MamReference maxClearDate = new MamReference ( 0 ) ;
2016-09-16 09:07:52 +00:00
while ( cursor . moveToNext ( ) ) {
try {
2017-05-07 19:05:35 +00:00
final JSONObject o = new JSONObject ( cursor . getString ( 0 ) ) ;
maxClearDate = MamReference . max ( maxClearDate , MamReference . fromAttribute ( o . getString ( Conversation . ATTRIBUTE_LAST_CLEAR_HISTORY ) ) ) ;
2016-09-16 09:07:52 +00:00
} catch ( Exception e ) {
//ignored
}
}
cursor . close ( ) ;
2017-05-07 19:05:35 +00:00
return maxClearDate ;
2016-09-16 09:07:52 +00:00
}
2017-06-18 14:35:30 +00:00
private Cursor getCursorForSession ( Account account , SignalProtocolAddress contact ) {
2015-05-29 09:17:26 +00:00
final SQLiteDatabase db = this . getReadableDatabase ( ) ;
String [ ] selectionArgs = { account . getUuid ( ) ,
contact . getName ( ) ,
Integer . toString ( contact . getDeviceId ( ) ) } ;
2016-09-16 09:07:52 +00:00
return db . query ( SQLiteAxolotlStore . SESSION_TABLENAME ,
null ,
2015-07-28 20:00:54 +00:00
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . NAME + " = ? AND "
+ SQLiteAxolotlStore . DEVICE_ID + " = ? " ,
2015-05-29 09:17:26 +00:00
selectionArgs ,
null , null , null ) ;
}
2017-06-18 14:35:30 +00:00
public SessionRecord loadSession ( Account account , SignalProtocolAddress contact ) {
2015-05-29 09:17:26 +00:00
SessionRecord session = null ;
2015-06-26 13:41:02 +00:00
Cursor cursor = getCursorForSession ( account , contact ) ;
2015-11-28 19:11:38 +00:00
if ( cursor . getCount ( ) ! = 0 ) {
2015-05-29 09:17:26 +00:00
cursor . moveToFirst ( ) ;
try {
2015-11-28 19:11:38 +00:00
session = new SessionRecord ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ;
2015-05-29 09:17:26 +00:00
} catch ( IOException e ) {
2015-06-29 11:40:56 +00:00
cursor . close ( ) ;
2015-05-29 09:17:26 +00:00
throw new AssertionError ( e ) ;
}
2015-06-26 13:41:02 +00:00
}
cursor . close ( ) ;
2015-05-29 09:17:26 +00:00
return session ;
}
2017-06-18 14:35:30 +00:00
public List < Integer > getSubDeviceSessions ( Account account , SignalProtocolAddress contact ) {
2015-05-29 09:17:26 +00:00
final SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-09-05 15:25:46 +00:00
return getSubDeviceSessions ( db , account , contact ) ;
}
2017-06-18 14:35:30 +00:00
private List < Integer > getSubDeviceSessions ( SQLiteDatabase db , Account account , SignalProtocolAddress contact ) {
2015-09-05 15:25:46 +00:00
List < Integer > devices = new ArrayList < > ( ) ;
2015-07-28 20:00:54 +00:00
String [ ] columns = { SQLiteAxolotlStore . DEVICE_ID } ;
2015-05-29 09:17:26 +00:00
String [ ] selectionArgs = { account . getUuid ( ) ,
contact . getName ( ) } ;
2015-07-28 20:00:54 +00:00
Cursor cursor = db . query ( SQLiteAxolotlStore . SESSION_TABLENAME ,
2015-05-29 09:17:26 +00:00
columns ,
2015-07-28 20:00:54 +00:00
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . NAME + " = ? " ,
2015-05-29 09:17:26 +00:00
selectionArgs ,
null , null , null ) ;
2015-11-28 19:11:38 +00:00
while ( cursor . moveToNext ( ) ) {
2015-05-29 09:17:26 +00:00
devices . add ( cursor . getInt (
2015-07-28 20:00:54 +00:00
cursor . getColumnIndex ( SQLiteAxolotlStore . DEVICE_ID ) ) ) ;
2015-05-29 09:17:26 +00:00
}
cursor . close ( ) ;
return devices ;
}
2017-06-29 12:17:45 +00:00
public List < String > getKnownSignalAddresses ( Account account ) {
List < String > addresses = new ArrayList < > ( ) ;
2018-05-17 18:17:00 +00:00
String [ ] colums = { " DISTINCT " + SQLiteAxolotlStore . NAME } ;
2017-06-29 12:17:45 +00:00
String [ ] selectionArgs = { account . getUuid ( ) } ;
Cursor cursor = getReadableDatabase ( ) . query ( SQLiteAxolotlStore . SESSION_TABLENAME ,
colums ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
selectionArgs ,
2018-05-17 18:17:00 +00:00
null , null , null
) ;
2017-06-29 12:17:45 +00:00
while ( cursor . moveToNext ( ) ) {
2017-07-29 11:50:32 +00:00
addresses . add ( cursor . getString ( 0 ) ) ;
2017-06-29 12:17:45 +00:00
}
cursor . close ( ) ;
return addresses ;
}
2017-06-18 14:35:30 +00:00
public boolean containsSession ( Account account , SignalProtocolAddress contact ) {
2015-05-29 09:17:26 +00:00
Cursor cursor = getCursorForSession ( account , contact ) ;
int count = cursor . getCount ( ) ;
cursor . close ( ) ;
return count ! = 0 ;
}
2017-06-18 14:35:30 +00:00
public void storeSession ( Account account , SignalProtocolAddress contact , SessionRecord session ) {
2015-05-29 09:17:26 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
ContentValues values = new ContentValues ( ) ;
2015-07-28 20:00:54 +00:00
values . put ( SQLiteAxolotlStore . NAME , contact . getName ( ) ) ;
values . put ( SQLiteAxolotlStore . DEVICE_ID , contact . getDeviceId ( ) ) ;
2015-11-28 19:11:38 +00:00
values . put ( SQLiteAxolotlStore . KEY , Base64 . encodeToString ( session . serialize ( ) , Base64 . DEFAULT ) ) ;
2015-07-28 20:00:54 +00:00
values . put ( SQLiteAxolotlStore . ACCOUNT , account . getUuid ( ) ) ;
db . insert ( SQLiteAxolotlStore . SESSION_TABLENAME , null , values ) ;
2015-05-29 09:17:26 +00:00
}
2017-06-18 14:35:30 +00:00
public void deleteSession ( Account account , SignalProtocolAddress contact ) {
2015-05-29 09:17:26 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2015-09-05 15:25:46 +00:00
deleteSession ( db , account , contact ) ;
}
2017-06-18 14:35:30 +00:00
private void deleteSession ( SQLiteDatabase db , Account account , SignalProtocolAddress contact ) {
2015-05-29 09:17:26 +00:00
String [ ] args = { account . getUuid ( ) ,
contact . getName ( ) ,
Integer . toString ( contact . getDeviceId ( ) ) } ;
2015-07-28 20:00:54 +00:00
db . delete ( SQLiteAxolotlStore . SESSION_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . NAME + " = ? AND "
+ SQLiteAxolotlStore . DEVICE_ID + " = ? " ,
2015-05-29 09:17:26 +00:00
args ) ;
}
2017-06-18 14:35:30 +00:00
public void deleteAllSessions ( Account account , SignalProtocolAddress contact ) {
2015-05-29 09:17:26 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { account . getUuid ( ) , contact . getName ( ) } ;
2015-07-28 20:00:54 +00:00
db . delete ( SQLiteAxolotlStore . SESSION_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " =? AND "
+ SQLiteAxolotlStore . NAME + " = ? " ,
2015-05-29 09:17:26 +00:00
args ) ;
}
private Cursor getCursorForPreKey ( Account account , int preKeyId ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-07-28 20:00:54 +00:00
String [ ] columns = { SQLiteAxolotlStore . KEY } ;
2015-05-29 09:17:26 +00:00
String [ ] selectionArgs = { account . getUuid ( ) , Integer . toString ( preKeyId ) } ;
2015-07-28 20:00:54 +00:00
Cursor cursor = db . query ( SQLiteAxolotlStore . PREKEY_TABLENAME ,
2015-05-29 09:17:26 +00:00
columns ,
2015-07-28 20:00:54 +00:00
SQLiteAxolotlStore . ACCOUNT + " =? AND "
+ SQLiteAxolotlStore . ID + " =? " ,
2015-05-29 09:17:26 +00:00
selectionArgs ,
null , null , null ) ;
return cursor ;
}
public PreKeyRecord loadPreKey ( Account account , int preKeyId ) {
PreKeyRecord record = null ;
Cursor cursor = getCursorForPreKey ( account , preKeyId ) ;
2015-11-28 19:11:38 +00:00
if ( cursor . getCount ( ) ! = 0 ) {
2015-05-29 09:17:26 +00:00
cursor . moveToFirst ( ) ;
try {
2015-11-28 19:11:38 +00:00
record = new PreKeyRecord ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ;
} catch ( IOException e ) {
2015-05-29 09:17:26 +00:00
throw new AssertionError ( e ) ;
}
}
cursor . close ( ) ;
return record ;
}
public boolean containsPreKey ( Account account , int preKeyId ) {
Cursor cursor = getCursorForPreKey ( account , preKeyId ) ;
int count = cursor . getCount ( ) ;
cursor . close ( ) ;
return count ! = 0 ;
}
public void storePreKey ( Account account , PreKeyRecord record ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
ContentValues values = new ContentValues ( ) ;
2015-07-28 20:00:54 +00:00
values . put ( SQLiteAxolotlStore . ID , record . getId ( ) ) ;
2015-11-28 19:11:38 +00:00
values . put ( SQLiteAxolotlStore . KEY , Base64 . encodeToString ( record . serialize ( ) , Base64 . DEFAULT ) ) ;
2015-07-28 20:00:54 +00:00
values . put ( SQLiteAxolotlStore . ACCOUNT , account . getUuid ( ) ) ;
db . insert ( SQLiteAxolotlStore . PREKEY_TABLENAME , null , values ) ;
2015-05-29 09:17:26 +00:00
}
public void deletePreKey ( Account account , int preKeyId ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { account . getUuid ( ) , Integer . toString ( preKeyId ) } ;
2015-07-28 20:00:54 +00:00
db . delete ( SQLiteAxolotlStore . PREKEY_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " =? AND "
+ SQLiteAxolotlStore . ID + " =? " ,
2015-05-29 09:17:26 +00:00
args ) ;
}
private Cursor getCursorForSignedPreKey ( Account account , int signedPreKeyId ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-07-28 20:00:54 +00:00
String [ ] columns = { SQLiteAxolotlStore . KEY } ;
2015-05-29 09:17:26 +00:00
String [ ] selectionArgs = { account . getUuid ( ) , Integer . toString ( signedPreKeyId ) } ;
2015-07-28 20:00:54 +00:00
Cursor cursor = db . query ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
2015-05-29 09:17:26 +00:00
columns ,
2015-07-28 20:00:54 +00:00
SQLiteAxolotlStore . ACCOUNT + " =? AND " + SQLiteAxolotlStore . ID + " =? " ,
2015-05-29 09:17:26 +00:00
selectionArgs ,
null , null , null ) ;
return cursor ;
}
public SignedPreKeyRecord loadSignedPreKey ( Account account , int signedPreKeyId ) {
SignedPreKeyRecord record = null ;
2015-06-25 14:56:34 +00:00
Cursor cursor = getCursorForSignedPreKey ( account , signedPreKeyId ) ;
2015-11-28 19:11:38 +00:00
if ( cursor . getCount ( ) ! = 0 ) {
2015-05-29 09:17:26 +00:00
cursor . moveToFirst ( ) ;
try {
2015-11-28 19:11:38 +00:00
record = new SignedPreKeyRecord ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ;
} catch ( IOException e ) {
2015-05-29 09:17:26 +00:00
throw new AssertionError ( e ) ;
}
}
cursor . close ( ) ;
return record ;
}
public List < SignedPreKeyRecord > loadSignedPreKeys ( Account account ) {
List < SignedPreKeyRecord > prekeys = new ArrayList < > ( ) ;
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-07-28 20:00:54 +00:00
String [ ] columns = { SQLiteAxolotlStore . KEY } ;
2015-05-29 09:17:26 +00:00
String [ ] selectionArgs = { account . getUuid ( ) } ;
2015-07-28 20:00:54 +00:00
Cursor cursor = db . query ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
2015-05-29 09:17:26 +00:00
columns ,
2015-07-28 20:00:54 +00:00
SQLiteAxolotlStore . ACCOUNT + " =? " ,
2015-05-29 09:17:26 +00:00
selectionArgs ,
null , null , null ) ;
2015-11-28 19:11:38 +00:00
while ( cursor . moveToNext ( ) ) {
2015-05-29 09:17:26 +00:00
try {
2015-07-28 20:00:54 +00:00
prekeys . add ( new SignedPreKeyRecord ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ) ;
2015-05-29 09:17:26 +00:00
} catch ( IOException ignored ) {
}
}
2015-06-29 11:40:56 +00:00
cursor . close ( ) ;
2015-05-29 09:17:26 +00:00
return prekeys ;
}
2017-05-04 09:03:58 +00:00
public int getSignedPreKeysCount ( Account account ) {
2018-05-17 18:17:00 +00:00
String [ ] columns = { " count( " + SQLiteAxolotlStore . KEY + " ) " } ;
2017-05-04 09:03:58 +00:00
String [ ] selectionArgs = { account . getUuid ( ) } ;
SQLiteDatabase db = this . getReadableDatabase ( ) ;
Cursor cursor = db . query ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
columns ,
SQLiteAxolotlStore . ACCOUNT + " =? " ,
selectionArgs ,
null , null , null ) ;
final int count ;
if ( cursor . moveToFirst ( ) ) {
count = cursor . getInt ( 0 ) ;
} else {
count = 0 ;
}
cursor . close ( ) ;
return count ;
}
2015-05-29 09:17:26 +00:00
public boolean containsSignedPreKey ( Account account , int signedPreKeyId ) {
Cursor cursor = getCursorForPreKey ( account , signedPreKeyId ) ;
int count = cursor . getCount ( ) ;
cursor . close ( ) ;
return count ! = 0 ;
}
public void storeSignedPreKey ( Account account , SignedPreKeyRecord record ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
ContentValues values = new ContentValues ( ) ;
2015-07-28 20:00:54 +00:00
values . put ( SQLiteAxolotlStore . ID , record . getId ( ) ) ;
2015-11-28 19:11:38 +00:00
values . put ( SQLiteAxolotlStore . KEY , Base64 . encodeToString ( record . serialize ( ) , Base64 . DEFAULT ) ) ;
2015-07-28 20:00:54 +00:00
values . put ( SQLiteAxolotlStore . ACCOUNT , account . getUuid ( ) ) ;
db . insert ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME , null , values ) ;
2015-05-29 09:17:26 +00:00
}
public void deleteSignedPreKey ( Account account , int signedPreKeyId ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { account . getUuid ( ) , Integer . toString ( signedPreKeyId ) } ;
2015-07-28 20:00:54 +00:00
db . delete ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " =? AND "
+ SQLiteAxolotlStore . ID + " =? " ,
2015-05-29 09:17:26 +00:00
args ) ;
}
2015-06-29 11:53:39 +00:00
private Cursor getIdentityKeyCursor ( Account account , String name , boolean own ) {
2015-09-05 15:25:46 +00:00
final SQLiteDatabase db = this . getReadableDatabase ( ) ;
return getIdentityKeyCursor ( db , account , name , own ) ;
2015-07-09 12:23:17 +00:00
}
2015-09-05 15:25:46 +00:00
private Cursor getIdentityKeyCursor ( SQLiteDatabase db , Account account , String name , boolean own ) {
2015-11-28 19:11:38 +00:00
return getIdentityKeyCursor ( db , account , name , own , null ) ;
2015-07-15 14:32:42 +00:00
}
2015-09-05 15:25:46 +00:00
private Cursor getIdentityKeyCursor ( Account account , String fingerprint ) {
2015-06-29 11:53:39 +00:00
final SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-09-05 15:25:46 +00:00
return getIdentityKeyCursor ( db , account , fingerprint ) ;
}
private Cursor getIdentityKeyCursor ( SQLiteDatabase db , Account account , String fingerprint ) {
return getIdentityKeyCursor ( db , account , null , null , fingerprint ) ;
}
private Cursor getIdentityKeyCursor ( SQLiteDatabase db , Account account , String name , Boolean own , String fingerprint ) {
2016-11-14 21:27:41 +00:00
String [ ] columns = { SQLiteAxolotlStore . TRUST ,
SQLiteAxolotlStore . ACTIVE ,
2016-11-19 12:34:54 +00:00
SQLiteAxolotlStore . LAST_ACTIVATION ,
2015-07-28 20:00:54 +00:00
SQLiteAxolotlStore . KEY } ;
2015-07-09 12:23:17 +00:00
ArrayList < String > selectionArgs = new ArrayList < > ( 4 ) ;
selectionArgs . add ( account . getUuid ( ) ) ;
2015-07-28 20:00:54 +00:00
String selectionString = SQLiteAxolotlStore . ACCOUNT + " = ? " ;
2015-11-28 19:11:38 +00:00
if ( name ! = null ) {
2015-07-15 14:32:42 +00:00
selectionArgs . add ( name ) ;
2015-07-28 20:00:54 +00:00
selectionString + = " AND " + SQLiteAxolotlStore . NAME + " = ? " ;
2015-07-15 14:32:42 +00:00
}
2015-11-28 19:11:38 +00:00
if ( fingerprint ! = null ) {
2015-07-09 12:23:17 +00:00
selectionArgs . add ( fingerprint ) ;
2015-07-28 20:00:54 +00:00
selectionString + = " AND " + SQLiteAxolotlStore . FINGERPRINT + " = ? " ;
2015-07-15 14:32:42 +00:00
}
2015-11-28 19:11:38 +00:00
if ( own ! = null ) {
selectionArgs . add ( own ? " 1 " : " 0 " ) ;
2015-07-28 20:00:54 +00:00
selectionString + = " AND " + SQLiteAxolotlStore . OWN + " = ? " ;
2015-07-09 12:23:17 +00:00
}
2015-07-28 20:00:54 +00:00
Cursor cursor = db . query ( SQLiteAxolotlStore . IDENTITIES_TABLENAME ,
2015-06-29 11:53:39 +00:00
columns ,
2015-07-09 12:23:17 +00:00
selectionString ,
selectionArgs . toArray ( new String [ selectionArgs . size ( ) ] ) ,
2015-06-29 11:53:39 +00:00
null , null , null ) ;
return cursor ;
}
2015-09-05 15:25:46 +00:00
public IdentityKeyPair loadOwnIdentityKeyPair ( Account account ) {
SQLiteDatabase db = getReadableDatabase ( ) ;
return loadOwnIdentityKeyPair ( db , account ) ;
}
private IdentityKeyPair loadOwnIdentityKeyPair ( SQLiteDatabase db , Account account ) {
2018-03-05 17:30:40 +00:00
String name = account . getJid ( ) . asBareJid ( ) . toString ( ) ;
2015-06-29 11:53:39 +00:00
IdentityKeyPair identityKeyPair = null ;
2015-09-05 15:25:46 +00:00
Cursor cursor = getIdentityKeyCursor ( db , account , name , true ) ;
2015-11-28 19:11:38 +00:00
if ( cursor . getCount ( ) ! = 0 ) {
2015-06-29 11:53:39 +00:00
cursor . moveToFirst ( ) ;
try {
2015-11-28 19:11:38 +00:00
identityKeyPair = new IdentityKeyPair ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ;
2015-06-29 11:53:39 +00:00
} catch ( InvalidKeyException e ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Encountered invalid IdentityKey in database for account " + account . getJid ( ) . asBareJid ( ) + " , address: " + name ) ;
2015-06-29 11:53:39 +00:00
}
}
cursor . close ( ) ;
return identityKeyPair ;
}
public Set < IdentityKey > loadIdentityKeys ( Account account , String name ) {
2015-07-19 16:36:28 +00:00
return loadIdentityKeys ( account , name , null ) ;
}
2016-11-14 21:27:41 +00:00
public Set < IdentityKey > loadIdentityKeys ( Account account , String name , FingerprintStatus status ) {
2015-06-29 11:53:39 +00:00
Set < IdentityKey > identityKeys = new HashSet < > ( ) ;
Cursor cursor = getIdentityKeyCursor ( account , name , false ) ;
2015-11-28 19:11:38 +00:00
while ( cursor . moveToNext ( ) ) {
2016-11-14 21:27:41 +00:00
if ( status ! = null & & ! FingerprintStatus . fromCursor ( cursor ) . equals ( status ) ) {
2015-07-19 16:36:28 +00:00
continue ;
}
2015-06-29 11:53:39 +00:00
try {
2016-11-17 19:09:42 +00:00
String key = cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) ;
if ( key ! = null ) {
identityKeys . add ( new IdentityKey ( Base64 . decode ( key , Base64 . DEFAULT ) , 0 ) ) ;
} else {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Missing key (possibly preverified) in database for account " + account . getJid ( ) . asBareJid ( ) + " , address: " + name ) ;
2016-11-17 19:09:42 +00:00
}
2015-06-29 11:53:39 +00:00
} catch ( InvalidKeyException e ) {
2018-03-05 17:30:40 +00:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Encountered invalid IdentityKey in database for account " + account . getJid ( ) . asBareJid ( ) + " , address: " + name ) ;
2015-06-29 11:53:39 +00:00
}
}
cursor . close ( ) ;
return identityKeys ;
}
2015-07-20 12:56:41 +00:00
public long numTrustedKeys ( Account account , String name ) {
SQLiteDatabase db = getReadableDatabase ( ) ;
String [ ] args = {
account . getUuid ( ) ,
2015-07-20 20:02:54 +00:00
name ,
2016-11-14 21:27:41 +00:00
FingerprintStatus . Trust . TRUSTED . toString ( ) ,
FingerprintStatus . Trust . VERIFIED . toString ( ) ,
FingerprintStatus . Trust . VERIFIED_X509 . toString ( )
2015-07-20 12:56:41 +00:00
} ;
2015-07-28 20:00:54 +00:00
return DatabaseUtils . queryNumEntries ( db , SQLiteAxolotlStore . IDENTITIES_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? "
2015-11-28 19:11:38 +00:00
+ " AND " + SQLiteAxolotlStore . NAME + " = ? "
2018-05-17 18:17:00 +00:00
+ " AND ( " + SQLiteAxolotlStore . TRUST + " = ? OR " + SQLiteAxolotlStore . TRUST + " = ? OR " + SQLiteAxolotlStore . TRUST + " = ?) "
+ " AND " + SQLiteAxolotlStore . ACTIVE + " > 0 " ,
2015-07-20 12:56:41 +00:00
args
) ;
}
2016-11-14 21:27:41 +00:00
private void storeIdentityKey ( Account account , String name , boolean own , String fingerprint , String base64Serialized , FingerprintStatus status ) {
2015-06-29 11:53:39 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
ContentValues values = new ContentValues ( ) ;
2015-07-28 20:00:54 +00:00
values . put ( SQLiteAxolotlStore . ACCOUNT , account . getUuid ( ) ) ;
values . put ( SQLiteAxolotlStore . NAME , name ) ;
values . put ( SQLiteAxolotlStore . OWN , own ? 1 : 0 ) ;
values . put ( SQLiteAxolotlStore . FINGERPRINT , fingerprint ) ;
values . put ( SQLiteAxolotlStore . KEY , base64Serialized ) ;
2016-11-14 21:27:41 +00:00
values . putAll ( status . toContentValues ( ) ) ;
2018-05-17 18:17:00 +00:00
String where = SQLiteAxolotlStore . ACCOUNT + " =? AND " + SQLiteAxolotlStore . NAME + " =? AND " + SQLiteAxolotlStore . FINGERPRINT + " =? " ;
String [ ] whereArgs = { account . getUuid ( ) , name , fingerprint } ;
int rows = db . update ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , values , where , whereArgs ) ;
2016-11-17 19:09:42 +00:00
if ( rows = = 0 ) {
db . insert ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , null , values ) ;
}
}
public void storePreVerification ( Account account , String name , String fingerprint , FingerprintStatus status ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
ContentValues values = new ContentValues ( ) ;
values . put ( SQLiteAxolotlStore . ACCOUNT , account . getUuid ( ) ) ;
values . put ( SQLiteAxolotlStore . NAME , name ) ;
values . put ( SQLiteAxolotlStore . OWN , 0 ) ;
values . put ( SQLiteAxolotlStore . FINGERPRINT , fingerprint ) ;
values . putAll ( status . toContentValues ( ) ) ;
2015-07-28 20:00:54 +00:00
db . insert ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , null , values ) ;
2015-06-29 11:53:39 +00:00
}
2016-11-14 21:27:41 +00:00
public FingerprintStatus getFingerprintStatus ( Account account , String fingerprint ) {
2015-07-15 14:32:42 +00:00
Cursor cursor = getIdentityKeyCursor ( account , fingerprint ) ;
2016-11-14 21:27:41 +00:00
final FingerprintStatus status ;
2015-07-09 12:23:17 +00:00
if ( cursor . getCount ( ) > 0 ) {
cursor . moveToFirst ( ) ;
2016-11-14 21:27:41 +00:00
status = FingerprintStatus . fromCursor ( cursor ) ;
} else {
status = null ;
2015-07-09 12:23:17 +00:00
}
cursor . close ( ) ;
2016-11-14 21:27:41 +00:00
return status ;
2015-07-09 12:23:17 +00:00
}
2016-11-14 21:27:41 +00:00
public boolean setIdentityKeyTrust ( Account account , String fingerprint , FingerprintStatus fingerprintStatus ) {
2015-07-09 12:23:17 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2016-11-14 21:27:41 +00:00
return setIdentityKeyTrust ( db , account , fingerprint , fingerprintStatus ) ;
2015-09-05 15:25:46 +00:00
}
2016-11-14 21:27:41 +00:00
private boolean setIdentityKeyTrust ( SQLiteDatabase db , Account account , String fingerprint , FingerprintStatus status ) {
2015-07-09 12:23:17 +00:00
String [ ] selectionArgs = {
account . getUuid ( ) ,
fingerprint
} ;
2016-11-14 21:27:41 +00:00
int rows = db . update ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , status . toContentValues ( ) ,
2015-07-28 20:00:54 +00:00
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
2015-11-28 19:11:38 +00:00
+ SQLiteAxolotlStore . FINGERPRINT + " = ? " ,
2015-07-09 12:23:17 +00:00
selectionArgs ) ;
return rows = = 1 ;
}
2015-12-23 16:41:26 +00:00
public boolean setIdentityKeyCertificate ( Account account , String fingerprint , X509Certificate x509Certificate ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] selectionArgs = {
account . getUuid ( ) ,
fingerprint
} ;
try {
ContentValues values = new ContentValues ( ) ;
values . put ( SQLiteAxolotlStore . CERTIFICATE , x509Certificate . getEncoded ( ) ) ;
return db . update ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , values ,
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . FINGERPRINT + " = ? " ,
selectionArgs ) = = 1 ;
} catch ( CertificateEncodingException e ) {
2015-12-23 18:18:53 +00:00
Log . d ( Config . LOGTAG , " could not encode certificate " ) ;
2015-12-23 16:41:26 +00:00
return false ;
}
}
2015-12-23 18:18:53 +00:00
public X509Certificate getIdentityKeyCertifcate ( Account account , String fingerprint ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
String [ ] selectionArgs = {
account . getUuid ( ) ,
fingerprint
} ;
String [ ] colums = { SQLiteAxolotlStore . CERTIFICATE } ;
String selection = SQLiteAxolotlStore . ACCOUNT + " = ? AND " + SQLiteAxolotlStore . FINGERPRINT + " = ? " ;
Cursor cursor = db . query ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , colums , selection , selectionArgs , null , null , null ) ;
if ( cursor . getCount ( ) < 1 ) {
return null ;
} else {
cursor . moveToFirst ( ) ;
byte [ ] certificate = cursor . getBlob ( cursor . getColumnIndex ( SQLiteAxolotlStore . CERTIFICATE ) ) ;
2016-06-12 10:50:31 +00:00
cursor . close ( ) ;
2015-12-23 18:18:53 +00:00
if ( certificate = = null | | certificate . length = = 0 ) {
return null ;
}
try {
CertificateFactory certificateFactory = CertificateFactory . getInstance ( " X.509 " ) ;
return ( X509Certificate ) certificateFactory . generateCertificate ( new ByteArrayInputStream ( certificate ) ) ;
} catch ( CertificateException e ) {
2018-05-17 18:17:00 +00:00
Log . d ( Config . LOGTAG , " certificate exception " + e . getMessage ( ) ) ;
2015-12-23 18:18:53 +00:00
return null ;
}
}
}
2016-11-17 19:09:42 +00:00
public void storeIdentityKey ( Account account , String name , IdentityKey identityKey , FingerprintStatus status ) {
2017-06-25 16:18:13 +00:00
storeIdentityKey ( account , name , false , CryptoHelper . bytesToHex ( identityKey . getPublicKey ( ) . serialize ( ) ) , Base64 . encodeToString ( identityKey . serialize ( ) , Base64 . DEFAULT ) , status ) ;
2015-06-29 11:53:39 +00:00
}
2015-09-05 15:25:46 +00:00
public void storeOwnIdentityKeyPair ( Account account , IdentityKeyPair identityKeyPair ) {
2018-03-05 17:30:40 +00:00
storeIdentityKey ( account , account . getJid ( ) . asBareJid ( ) . toString ( ) , true , CryptoHelper . bytesToHex ( identityKeyPair . getPublicKey ( ) . serialize ( ) ) , Base64 . encodeToString ( identityKeyPair . serialize ( ) , Base64 . DEFAULT ) , FingerprintStatus . createActiveVerified ( false ) ) ;
2015-06-29 11:53:39 +00:00
}
2015-07-07 17:30:08 +00:00
2015-07-20 11:15:49 +00:00
2017-08-10 12:17:47 +00:00
private void recreateAxolotlDb ( SQLiteDatabase db ) {
2015-11-28 19:11:38 +00:00
Log . d ( Config . LOGTAG , AxolotlService . LOGPREFIX + " : " + " >>> (RE)CREATING AXOLOTL DATABASE <<< " ) ;
2015-07-28 20:00:54 +00:00
db . execSQL ( " DROP TABLE IF EXISTS " + SQLiteAxolotlStore . SESSION_TABLENAME ) ;
2015-07-07 17:30:08 +00:00
db . execSQL ( CREATE_SESSIONS_STATEMENT ) ;
2015-07-28 20:00:54 +00:00
db . execSQL ( " DROP TABLE IF EXISTS " + SQLiteAxolotlStore . PREKEY_TABLENAME ) ;
2015-07-07 17:30:08 +00:00
db . execSQL ( CREATE_PREKEYS_STATEMENT ) ;
2015-07-28 20:00:54 +00:00
db . execSQL ( " DROP TABLE IF EXISTS " + SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ) ;
2015-07-07 17:30:08 +00:00
db . execSQL ( CREATE_SIGNED_PREKEYS_STATEMENT ) ;
2015-07-28 20:00:54 +00:00
db . execSQL ( " DROP TABLE IF EXISTS " + SQLiteAxolotlStore . IDENTITIES_TABLENAME ) ;
2015-07-07 17:30:08 +00:00
db . execSQL ( CREATE_IDENTITIES_STATEMENT ) ;
}
2015-11-28 19:11:38 +00:00
2015-07-07 17:36:22 +00:00
public void wipeAxolotlDb ( Account account ) {
String accountName = account . getUuid ( ) ;
2015-11-28 19:11:38 +00:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " >>> WIPING AXOLOTL DATABASE FOR ACCOUNT " + accountName + " <<< " ) ;
2015-07-07 17:36:22 +00:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2015-11-28 19:11:38 +00:00
String [ ] deleteArgs = {
2015-07-07 17:36:22 +00:00
accountName
} ;
2015-07-28 20:00:54 +00:00
db . delete ( SQLiteAxolotlStore . SESSION_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
2015-07-07 17:36:22 +00:00
deleteArgs ) ;
2015-07-28 20:00:54 +00:00
db . delete ( SQLiteAxolotlStore . PREKEY_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
2015-07-07 17:36:22 +00:00
deleteArgs ) ;
2015-07-28 20:00:54 +00:00
db . delete ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
2015-07-07 17:36:22 +00:00
deleteArgs ) ;
2015-07-28 20:00:54 +00:00
db . delete ( SQLiteAxolotlStore . IDENTITIES_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
2015-07-07 17:36:22 +00:00
deleteArgs ) ;
}
2016-11-08 11:20:07 +00:00
2017-05-31 14:45:51 +00:00
public List < ShortcutService . FrequentContact > getFrequentContacts ( int days ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2018-05-17 18:17:00 +00:00
final String SQL = " select " + Conversation . TABLENAME + " . " + Conversation . ACCOUNT + " , " + Conversation . TABLENAME + " . " + Conversation . CONTACTJID + " from " + Conversation . TABLENAME + " join " + Message . TABLENAME + " on conversations.uuid=messages.conversationUuid where messages.status!=0 and carbon==0 and conversations.mode=0 and messages.timeSent>=? group by conversations.uuid order by count(body) desc limit 4; " ;
2017-05-31 14:45:51 +00:00
String [ ] whereArgs = new String [ ] { String . valueOf ( System . currentTimeMillis ( ) - ( Config . MILLISECONDS_IN_DAY * days ) ) } ;
2018-05-17 18:17:00 +00:00
Cursor cursor = db . rawQuery ( SQL , whereArgs ) ;
2017-05-31 14:45:51 +00:00
ArrayList < ShortcutService . FrequentContact > contacts = new ArrayList < > ( ) ;
2018-05-17 18:17:00 +00:00
while ( cursor . moveToNext ( ) ) {
2017-05-31 14:45:51 +00:00
try {
2018-03-05 17:30:40 +00:00
contacts . add ( new ShortcutService . FrequentContact ( cursor . getString ( 0 ) , Jid . of ( cursor . getString ( 1 ) ) ) ) ;
2017-05-31 14:45:51 +00:00
} catch ( Exception e ) {
2018-05-17 18:17:00 +00:00
Log . d ( Config . LOGTAG , e . getMessage ( ) ) ;
2017-05-31 14:45:51 +00:00
}
}
cursor . close ( ) ;
return contacts ;
}
2014-01-24 22:58:51 +00:00
}