2014-02-28 18:46:01 +01:00
package eu.siacs.conversations.persistance ;
2014-01-24 23:58:51 +01:00
2015-06-25 16:56:34 +02:00
import android.content.ContentValues ;
import android.content.Context ;
import android.database.Cursor ;
2015-07-20 14:56:41 +02:00
import android.database.DatabaseUtils ;
2015-06-25 16:56:34 +02:00
import android.database.sqlite.SQLiteCantOpenDatabaseException ;
import android.database.sqlite.SQLiteDatabase ;
import android.database.sqlite.SQLiteOpenHelper ;
import android.util.Base64 ;
import android.util.Log ;
import org.whispersystems.libaxolotl.AxolotlAddress ;
2015-06-29 13:53:39 +02:00
import org.whispersystems.libaxolotl.IdentityKey ;
import org.whispersystems.libaxolotl.IdentityKeyPair ;
import org.whispersystems.libaxolotl.InvalidKeyException ;
2015-06-25 16:56:34 +02:00
import org.whispersystems.libaxolotl.state.PreKeyRecord ;
import org.whispersystems.libaxolotl.state.SessionRecord ;
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord ;
2015-05-29 11:17:26 +02:00
import java.io.IOException ;
2014-01-24 23:58:51 +01:00
import java.util.ArrayList ;
2015-06-29 13:53:39 +02:00
import java.util.HashSet ;
2015-09-20 23:17:32 +02:00
import java.util.Iterator ;
2014-01-24 23:58:51 +01:00
import java.util.List ;
2015-06-29 13:53:39 +02:00
import java.util.Set ;
2014-03-11 17:47:05 +01:00
import java.util.concurrent.CopyOnWriteArrayList ;
2014-01-24 23:58:51 +01:00
2015-05-14 15:25:52 +02:00
import eu.siacs.conversations.Config ;
2015-05-29 11:17:26 +02:00
import eu.siacs.conversations.crypto.axolotl.AxolotlService ;
2015-07-28 22:00:54 +02:00
import eu.siacs.conversations.crypto.axolotl.SQLiteAxolotlStore ;
2015-08-01 18:27:52 +02:00
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession ;
2014-02-28 18:46:01 +01: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 ;
2014-05-19 15:15:09 +02:00
import eu.siacs.conversations.entities.Roster ;
2015-05-14 15:25:52 +02:00
import eu.siacs.conversations.xmpp.jid.InvalidJidException ;
2014-11-05 21:55:47 +01:00
import eu.siacs.conversations.xmpp.jid.Jid ;
2014-01-24 23:58:51 +01:00
public class DatabaseBackend extends SQLiteOpenHelper {
2014-01-26 03:27:55 +01:00
2014-01-24 23:58:51 +01:00
private static DatabaseBackend instance = null ;
2014-01-26 03:27:55 +01:00
2014-01-24 23:58:51 +01:00
private static final String DATABASE_NAME = " history " ;
2015-09-05 17:25:46 +02:00
private static final int DATABASE_VERSION = 17 ;
2014-05-19 15:15:09 +02:00
private static String CREATE_CONTATCS_STATEMENT = " create table "
2014-07-29 14:42:17 +02: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 20:53:13 +02:00
+ Contact . SYSTEMACCOUNT + " NUMBER, " + Contact . AVATAR + " TEXT, "
2015-06-26 15:41:02 +02:00
+ Contact . LAST_PRESENCE + " TEXT, " + Contact . LAST_TIME + " NUMBER, "
2014-11-16 17:21:21 +01:00
+ Contact . GROUPS + " TEXT, FOREIGN KEY( " + Contact . ACCOUNT + " ) REFERENCES "
2014-08-24 20:53:13 +02:00
+ Account . TABLENAME + " ( " + Account . UUID
+ " ) ON DELETE CASCADE, UNIQUE( " + Contact . ACCOUNT + " , "
+ Contact . JID + " ) ON CONFLICT REPLACE); " ;
2014-01-24 23:58:51 +01:00
2015-05-29 11:17:26 +02:00
private static String CREATE_PREKEYS_STATEMENT = " CREATE TABLE "
2015-07-28 22:00:54 +02:00
+ SQLiteAxolotlStore . PREKEY_TABLENAME + " ( "
+ SQLiteAxolotlStore . ACCOUNT + " TEXT, "
+ SQLiteAxolotlStore . ID + " INTEGER, "
+ SQLiteAxolotlStore . KEY + " TEXT, FOREIGN KEY( "
+ SQLiteAxolotlStore . ACCOUNT
2015-05-29 11:17:26 +02:00
+ " ) REFERENCES " + Account . TABLENAME + " ( " + Account . UUID + " ) ON DELETE CASCADE, "
2015-07-28 22:00:54 +02:00
+ " UNIQUE( " + SQLiteAxolotlStore . ACCOUNT + " , "
+ SQLiteAxolotlStore . ID
2015-05-29 11:17:26 +02:00
+ " ) ON CONFLICT REPLACE "
+ " ); " ;
private static String CREATE_SIGNED_PREKEYS_STATEMENT = " CREATE TABLE "
2015-07-28 22:00:54 +02:00
+ SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME + " ( "
+ SQLiteAxolotlStore . ACCOUNT + " TEXT, "
+ SQLiteAxolotlStore . ID + " INTEGER, "
+ SQLiteAxolotlStore . KEY + " TEXT, FOREIGN KEY( "
+ SQLiteAxolotlStore . ACCOUNT
2015-05-29 11:17:26 +02:00
+ " ) REFERENCES " + Account . TABLENAME + " ( " + Account . UUID + " ) ON DELETE CASCADE, "
2015-07-28 22:00:54 +02:00
+ " UNIQUE( " + SQLiteAxolotlStore . ACCOUNT + " , "
+ SQLiteAxolotlStore . ID
2015-05-29 11:17:26 +02:00
+ " ) ON CONFLICT REPLACE " +
" ); " ;
private static String CREATE_SESSIONS_STATEMENT = " CREATE TABLE "
2015-07-28 22:00:54 +02:00
+ SQLiteAxolotlStore . SESSION_TABLENAME + " ( "
+ SQLiteAxolotlStore . ACCOUNT + " TEXT, "
+ SQLiteAxolotlStore . NAME + " TEXT, "
+ SQLiteAxolotlStore . DEVICE_ID + " INTEGER, "
+ SQLiteAxolotlStore . KEY + " TEXT, FOREIGN KEY( "
+ SQLiteAxolotlStore . ACCOUNT
2015-05-29 11:17:26 +02:00
+ " ) REFERENCES " + Account . TABLENAME + " ( " + Account . UUID + " ) ON DELETE CASCADE, "
2015-07-28 22:00:54 +02:00
+ " UNIQUE( " + SQLiteAxolotlStore . ACCOUNT + " , "
+ SQLiteAxolotlStore . NAME + " , "
+ SQLiteAxolotlStore . DEVICE_ID
2015-05-29 11:17:26 +02:00
+ " ) ON CONFLICT REPLACE "
+ " ); " ;
2015-06-29 13:53:39 +02:00
private static String CREATE_IDENTITIES_STATEMENT = " CREATE TABLE "
2015-07-28 22:00:54 +02:00
+ SQLiteAxolotlStore . IDENTITIES_TABLENAME + " ( "
+ SQLiteAxolotlStore . ACCOUNT + " TEXT, "
+ SQLiteAxolotlStore . NAME + " TEXT, "
+ SQLiteAxolotlStore . OWN + " INTEGER, "
+ SQLiteAxolotlStore . FINGERPRINT + " TEXT, "
+ SQLiteAxolotlStore . TRUSTED + " INTEGER, "
+ SQLiteAxolotlStore . KEY + " TEXT, FOREIGN KEY( "
+ SQLiteAxolotlStore . ACCOUNT
2015-07-10 02:24:33 +02:00
+ " ) REFERENCES " + Account . TABLENAME + " ( " + Account . UUID + " ) ON DELETE CASCADE, "
2015-07-28 22:00:54 +02:00
+ " UNIQUE( " + SQLiteAxolotlStore . ACCOUNT + " , "
+ SQLiteAxolotlStore . NAME + " , "
+ SQLiteAxolotlStore . FINGERPRINT
2015-07-10 02:24:33 +02:00
+ " ) ON CONFLICT IGNORE "
2015-06-29 13:53:39 +02:00
+ " ); " ;
2014-09-19 17:21:33 +02:00
private DatabaseBackend ( Context context ) {
2014-01-24 23:58:51 +01:00
super ( context , DATABASE_NAME , null , DATABASE_VERSION ) ;
}
@Override
public void onCreate ( SQLiteDatabase db ) {
2014-01-29 00:15:38 +01:00
db . execSQL ( " PRAGMA foreign_keys=ON; " ) ;
db . execSQL ( " create table " + Account . TABLENAME + " ( " + Account . UUID
2014-02-02 16:05:15 +01:00
+ " TEXT PRIMARY KEY, " + Account . USERNAME + " TEXT, "
+ Account . SERVER + " TEXT, " + Account . PASSWORD + " TEXT, "
+ Account . ROSTERVERSION + " TEXT, " + Account . OPTIONS
2014-08-24 20:53:13 +02:00
+ " NUMBER, " + Account . AVATAR + " TEXT, " + Account . KEYS
+ " TEXT) " ) ;
2014-01-26 03:27:55 +01:00
db . execSQL ( " create table " + Conversation . TABLENAME + " ( "
2014-01-27 20:40:42 +01:00
+ Conversation . UUID + " TEXT PRIMARY KEY, " + Conversation . NAME
2014-02-10 15:24:34 +01:00
+ " TEXT, " + Conversation . CONTACT + " TEXT, "
+ Conversation . ACCOUNT + " TEXT, " + Conversation . CONTACTJID
2014-01-27 20:40:42 +01:00
+ " TEXT, " + Conversation . CREATED + " NUMBER, "
2014-09-27 18:16:31 +02:00
+ Conversation . STATUS + " NUMBER, " + Conversation . MODE
2014-09-28 15:21:56 +02:00
+ " NUMBER, " + Conversation . ATTRIBUTES + " TEXT, FOREIGN KEY( "
+ Conversation . ACCOUNT + " ) REFERENCES " + Account . TABLENAME
+ " ( " + Account . UUID + " ) ON DELETE CASCADE); " ) ;
2014-01-27 20:40:42 +01:00
db . execSQL ( " create table " + Message . TABLENAME + " ( " + Message . UUID
2014-01-29 00:15:38 +01:00
+ " TEXT PRIMARY KEY, " + Message . CONVERSATION + " TEXT, "
+ Message . TIME_SENT + " NUMBER, " + Message . COUNTERPART
2014-07-29 14:42:17 +02:00
+ " TEXT, " + Message . TRUE_COUNTERPART + " TEXT, "
+ Message . BODY + " TEXT, " + Message . ENCRYPTION + " NUMBER, "
2014-08-24 20:53:13 +02:00
+ Message . STATUS + " NUMBER, " + Message . TYPE + " NUMBER, "
2014-11-13 21:04:05 +01:00
+ Message . RELATIVE_FILE_PATH + " TEXT, "
2014-12-09 21:41:49 +01:00
+ Message . SERVER_MSG_ID + " TEXT, "
2015-07-09 14:23:17 +02:00
+ Message . FINGERPRINT + " TEXT, "
2015-07-31 13:08:35 +02:00
+ Message . CARBON + " INTEGER, "
2014-08-24 20:53:13 +02:00
+ Message . REMOTE_MSG_ID + " TEXT, FOREIGN KEY( "
+ Message . CONVERSATION + " ) REFERENCES "
+ Conversation . TABLENAME + " ( " + Conversation . UUID
+ " ) ON DELETE CASCADE); " ) ;
2014-05-19 15:15:09 +02:00
db . execSQL ( CREATE_CONTATCS_STATEMENT ) ;
2015-06-29 13:40:56 +02:00
db . execSQL ( CREATE_SESSIONS_STATEMENT ) ;
db . execSQL ( CREATE_PREKEYS_STATEMENT ) ;
db . execSQL ( CREATE_SIGNED_PREKEYS_STATEMENT ) ;
2015-06-29 13:53:39 +02:00
db . execSQL ( CREATE_IDENTITIES_STATEMENT ) ;
2014-01-24 23:58:51 +01:00
}
@Override
2014-04-03 22:28:37 +02:00
public void onUpgrade ( SQLiteDatabase db , int oldVersion , int newVersion ) {
if ( oldVersion < 2 & & newVersion > = 2 ) {
2014-05-19 15:15:09 +02:00
db . execSQL ( " update " + Account . TABLENAME + " set "
+ Account . OPTIONS + " = " + Account . OPTIONS + " | 8 " ) ;
2014-04-03 22:28:37 +02:00
}
2014-04-06 15:34:08 +02:00
if ( oldVersion < 3 & & newVersion > = 3 ) {
2014-05-19 15:15:09 +02:00
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . TYPE + " NUMBER " ) ;
}
if ( oldVersion < 5 & & newVersion > = 5 ) {
2014-07-29 14:42:17 +02:00
db . execSQL ( " DROP TABLE " + Contact . TABLENAME ) ;
2014-05-19 15:15:09 +02:00
db . execSQL ( CREATE_CONTATCS_STATEMENT ) ;
2014-07-29 14:42:17 +02: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 15:34:08 +02:00
}
2014-08-21 12:32:50 +02: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 18:16:31 +02:00
if ( oldVersion < 8 & & newVersion > = 8 ) {
db . execSQL ( " ALTER TABLE " + Conversation . TABLENAME + " ADD COLUMN "
+ Conversation . ATTRIBUTES + " TEXT " ) ;
}
2015-06-26 15:41:02 +02: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 21:04:05 +01:00
if ( oldVersion < 10 & & newVersion > = 10 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . RELATIVE_FILE_PATH + " TEXT " ) ;
}
2014-11-16 17:21:21 +01:00
if ( oldVersion < 11 & & newVersion > = 11 ) {
db . execSQL ( " ALTER TABLE " + Contact . TABLENAME + " ADD COLUMN "
+ Contact . GROUPS + " TEXT " ) ;
db . execSQL ( " delete from " + Contact . TABLENAME ) ;
db . execSQL ( " update " + Account . TABLENAME + " set " + Account . ROSTERVERSION + " = NULL " ) ;
}
2014-12-09 21:41:49 +01:00
if ( oldVersion < 12 & & newVersion > = 12 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . SERVER_MSG_ID + " TEXT " ) ;
}
2015-01-02 01:21:14 +01:00
if ( oldVersion < 13 & & newVersion > = 13 ) {
db . execSQL ( " delete from " + Contact . TABLENAME ) ;
db . execSQL ( " update " + Account . TABLENAME + " set " + Account . ROSTERVERSION + " = NULL " ) ;
}
2015-05-14 15:25:52 +02:00
if ( oldVersion < 14 & & newVersion > = 14 ) {
// 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 {
newJid = Jid . fromString (
cursor . getString ( cursor . getColumnIndex ( Conversation . CONTACTJID ) )
) . toString ( ) ;
} catch ( InvalidJidException ignored ) {
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 {
newJid = Jid . fromString (
cursor . getString ( cursor . getColumnIndex ( Contact . JID ) )
) . toString ( ) ;
} catch ( InvalidJidException ignored ) {
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 {
newServer = Jid . fromParts (
cursor . getString ( cursor . getColumnIndex ( Account . USERNAME ) ) ,
cursor . getString ( cursor . getColumnIndex ( Account . SERVER ) ) ,
" mobile "
) . getDomainpart ( ) ;
} catch ( InvalidJidException ignored ) {
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 ( ) ;
}
2015-06-25 16:56:34 +02:00
if ( oldVersion < 15 & & newVersion > = 15 ) {
2015-07-20 13:15:49 +02:00
recreateAxolotlDb ( db ) ;
2015-07-09 14:23:17 +02:00
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . FINGERPRINT + " TEXT " ) ;
2015-06-25 16:56:34 +02:00
}
2015-07-29 16:41:58 +02:00
if ( oldVersion < 16 & & newVersion > = 16 ) {
db . execSQL ( " ALTER TABLE " + Message . TABLENAME + " ADD COLUMN "
+ Message . CARBON + " INTEGER " ) ;
}
2015-09-05 17:25:46 +02:00
if ( oldVersion < 17 & & newVersion > = 17 ) {
List < Account > accounts = getAccounts ( db ) ;
for ( Account account : accounts ) {
String ownDeviceIdString = account . getKey ( SQLiteAxolotlStore . JSONKEY_REGISTRATION_ID ) ;
if ( ownDeviceIdString = = null ) {
continue ;
}
int ownDeviceId = Integer . valueOf ( ownDeviceIdString ) ;
AxolotlAddress ownAddress = new AxolotlAddress ( account . getJid ( ) . toBareJid ( ) . toString ( ) , ownDeviceId ) ;
deleteSession ( db , account , ownAddress ) ;
IdentityKeyPair identityKeyPair = loadOwnIdentityKeyPair ( db , account ) ;
2015-09-05 18:47:37 +02:00
if ( identityKeyPair ! = null ) {
setIdentityKeyTrust ( db , account , identityKeyPair . getPublicKey ( ) . getFingerprint ( ) . replaceAll ( " \\ s " , " " ) , XmppAxolotlSession . Trust . TRUSTED ) ;
} else {
Log . d ( Config . LOGTAG , account . getJid ( ) . toBareJid ( ) + " : could not load own identity key pair " ) ;
}
2015-09-05 17:25:46 +02:00
}
}
2014-01-24 23:58:51 +01:00
}
2014-01-26 03:27:55 +01:00
2014-01-24 23:58:51 +01:00
public static synchronized DatabaseBackend getInstance ( Context context ) {
if ( instance = = null ) {
2014-01-25 19:33:12 +01:00
instance = new DatabaseBackend ( context ) ;
2014-01-24 23:58:51 +01:00
}
return instance ;
}
2014-01-26 03:27:55 +01:00
2014-01-27 20:40:42 +01:00
public void createConversation ( Conversation conversation ) {
2014-01-24 23:58:51 +01:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2014-01-27 20:40:42 +01: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 23:58:51 +01:00
}
2014-01-29 00:15:38 +01:00
2014-01-28 19:21:54 +01:00
public void createAccount ( Account account ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2014-01-29 00:15:38 +01:00
db . insert ( Account . TABLENAME , null , account . getContentValues ( ) ) ;
2014-01-28 19:21:54 +01:00
}
2014-05-19 15:15:09 +02:00
2014-02-05 22:33:39 +01:00
public void createContact ( Contact contact ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
db . insert ( Contact . TABLENAME , null , contact . getContentValues ( ) ) ;
}
2014-01-26 03:27:55 +01:00
2014-01-24 23:58:51 +01:00
public int getConversationCount ( ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2014-01-29 00:15:38 +01:00
Cursor cursor = db . rawQuery ( " select count(uuid) as count from "
+ Conversation . TABLENAME + " where " + Conversation . STATUS
+ " = " + Conversation . STATUS_AVAILABLE , null ) ;
2014-01-24 23:58:51 +01:00
cursor . moveToFirst ( ) ;
2014-11-16 00:34:16 +01:00
int count = cursor . getInt ( 0 ) ;
cursor . close ( ) ;
return count ;
2014-01-24 23:58:51 +01:00
}
2014-07-12 12:41:37 +02:00
public CopyOnWriteArrayList < Conversation > getConversations ( int status ) {
2014-11-05 21:55:47 +01:00
CopyOnWriteArrayList < Conversation > list = new CopyOnWriteArrayList < > ( ) ;
2014-01-24 23:58:51 +01:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2014-09-01 10:40:45 +02:00
String [ ] selectionArgs = { Integer . toString ( status ) } ;
2014-01-27 20:40:42 +01:00
Cursor cursor = db . rawQuery ( " select * from " + Conversation . TABLENAME
+ " where " + Conversation . STATUS + " = ? order by "
+ Conversation . CREATED + " desc " , selectionArgs ) ;
2014-01-26 03:27:55 +01:00
while ( cursor . moveToNext ( ) ) {
2014-01-24 23:58:51 +01:00
list . add ( Conversation . fromCursor ( cursor ) ) ;
}
2014-11-16 00:34:16 +01:00
cursor . close ( ) ;
2014-01-24 23:58:51 +01:00
return list ;
}
2014-07-29 14:42:17 +02:00
2014-10-20 21:08:33 +02:00
public ArrayList < Message > getMessages ( Conversation conversations , int limit ) {
2014-07-29 14:42:17 +02:00
return getMessages ( conversations , limit , - 1 ) ;
2014-06-14 16:59:07 +02:00
}
2014-01-24 23:58:51 +01:00
2014-10-20 21:08:33 +02:00
public ArrayList < Message > getMessages ( Conversation conversation , int limit ,
long timestamp ) {
2014-11-05 21:55:47 +01:00
ArrayList < Message > list = new ArrayList < > ( ) ;
2014-01-27 20:40:42 +01:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2014-06-14 16:59:07 +02:00
Cursor cursor ;
2014-07-29 14:42:17 +02:00
if ( timestamp = = - 1 ) {
2014-06-14 16:59:07 +02:00
String [ ] selectionArgs = { conversation . getUuid ( ) } ;
cursor = db . query ( Message . TABLENAME , null , Message . CONVERSATION
2014-07-29 14:42:17 +02:00
+ " =? " , selectionArgs , null , null , Message . TIME_SENT
+ " DESC " , String . valueOf ( limit ) ) ;
2014-06-14 16:59:07 +02:00
} else {
2014-09-08 23:58:37 +02:00
String [ ] selectionArgs = { conversation . getUuid ( ) ,
Long . toString ( timestamp ) } ;
2014-06-14 16:59:07 +02:00
cursor = db . query ( Message . TABLENAME , null , Message . CONVERSATION
2014-07-29 14:42:17 +02:00
+ " =? and " + Message . TIME_SENT + " <? " , selectionArgs ,
null , null , Message . TIME_SENT + " DESC " ,
2014-06-14 16:59:07 +02:00
String . valueOf ( limit ) ) ;
}
2014-01-29 00:15:38 +01:00
if ( cursor . getCount ( ) > 0 ) {
2014-01-27 20:40:42 +01:00
cursor . moveToLast ( ) ;
do {
2014-10-19 23:13:55 +02:00
Message message = Message . fromCursor ( cursor ) ;
message . setConversation ( conversation ) ;
list . add ( message ) ;
2014-01-27 20:40:42 +01:00
} while ( cursor . moveToPrevious ( ) ) ;
}
2014-11-16 00:34:16 +01:00
cursor . close ( ) ;
2014-01-27 20:40:42 +01:00
return list ;
}
2015-09-20 23:17:32 +02:00
public Iterable < Message > getMessagesIterable ( final Conversation conversation ) {
return new Iterable < Message > ( ) {
@Override
public Iterator < Message > iterator ( ) {
class MessageIterator implements Iterator < Message > {
SQLiteDatabase db = getReadableDatabase ( ) ;
String [ ] selectionArgs = { conversation . getUuid ( ) } ;
Cursor cursor = db . query ( Message . TABLENAME , null , Message . CONVERSATION
+ " =? " , selectionArgs , null , null , Message . TIME_SENT
+ " ASC " , null ) ;
public MessageIterator ( ) {
cursor . moveToFirst ( ) ;
}
@Override
public boolean hasNext ( ) {
return ! cursor . isAfterLast ( ) ;
}
@Override
public Message next ( ) {
Message message = Message . fromCursor ( cursor ) ;
cursor . moveToNext ( ) ;
return message ;
}
@Override
public void remove ( ) {
throw new UnsupportedOperationException ( ) ;
}
}
return new MessageIterator ( ) ;
}
} ;
}
2014-11-05 21:55:47 +01:00
public Conversation findConversation ( final Account account , final Jid contactJid ) {
2014-01-27 20:40:42 +01:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-01-21 16:18:57 +01:00
String [ ] selectionArgs = { account . getUuid ( ) ,
contactJid . toBareJid ( ) . toString ( ) + " /% " ,
contactJid . toBareJid ( ) . toString ( )
} ;
2014-01-29 00:15:38 +01:00
Cursor cursor = db . query ( Conversation . TABLENAME , null ,
2015-01-21 16:18:57 +01:00
Conversation . ACCOUNT + " =? AND ( " + Conversation . CONTACTJID
2015-05-29 11:17:26 +02:00
+ " like ? OR " + Conversation . CONTACTJID + " =?) " , selectionArgs , null , null , null ) ;
2014-01-29 00:15:38 +01:00
if ( cursor . getCount ( ) = = 0 )
return null ;
2014-01-27 20:40:42 +01:00
cursor . moveToFirst ( ) ;
2014-11-16 00:34:16 +01:00
Conversation conversation = Conversation . fromCursor ( cursor ) ;
cursor . close ( ) ;
return conversation ;
2014-01-27 20:40:42 +01:00
}
2014-12-21 21:43:58 +01:00
public void updateConversation ( final Conversation conversation ) {
final SQLiteDatabase db = this . getWritableDatabase ( ) ;
final String [ ] args = { conversation . getUuid ( ) } ;
2014-01-29 00:15:38 +01:00
db . update ( Conversation . TABLENAME , conversation . getContentValues ( ) ,
Conversation . UUID + " =? " , args ) ;
2014-01-27 20:40:42 +01:00
}
2014-01-29 00:15:38 +01:00
2014-01-28 19:21:54 +01:00
public List < Account > getAccounts ( ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-09-05 17:25:46 +02:00
return getAccounts ( db ) ;
}
private List < Account > getAccounts ( SQLiteDatabase db ) {
List < Account > list = new ArrayList < > ( ) ;
2014-01-29 00:15:38 +01:00
Cursor cursor = db . query ( Account . TABLENAME , null , null , null , null ,
null , null ) ;
2014-01-28 19:21:54 +01:00
while ( cursor . moveToNext ( ) ) {
list . add ( Account . fromCursor ( cursor ) ) ;
}
2014-10-08 14:10:37 +02:00
cursor . close ( ) ;
2014-01-28 19:21:54 +01:00
return list ;
}
public void updateAccount ( Account account ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2014-01-29 00:15:38 +01:00
String [ ] args = { account . getUuid ( ) } ;
db . update ( Account . TABLENAME , account . getContentValues ( ) , Account . UUID
+ " =? " , args ) ;
2014-01-28 19:21:54 +01:00
}
public void deleteAccount ( Account account ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2014-01-29 00:15:38 +01:00
String [ ] args = { account . getUuid ( ) } ;
db . delete ( Account . TABLENAME , Account . UUID + " =? " , args ) ;
2014-01-28 19:21:54 +01:00
}
2014-09-28 15:21:56 +02:00
2014-09-19 17:21:33 +02:00
public boolean hasEnabledAccounts ( ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2014-09-28 15:21:56 +02:00
Cursor cursor = db . rawQuery ( " select count( " + Account . UUID + " ) from "
+ Account . TABLENAME + " where not options & (1 <<1) " , null ) ;
2014-10-14 18:26:45 +02:00
try {
cursor . moveToFirst ( ) ;
int count = cursor . getInt ( 0 ) ;
cursor . close ( ) ;
return ( count > 0 ) ;
} catch ( SQLiteCantOpenDatabaseException e ) {
2014-10-15 19:32:12 +02:00
return true ; // better safe than sorry
2015-02-28 12:03:53 +01:00
} catch ( RuntimeException e ) {
return true ; // better safe than sorry
2014-10-14 18:26:45 +02:00
}
2014-09-19 17:21:33 +02:00
}
2014-01-27 20:40:42 +01:00
2014-01-29 00:15:38 +01:00
@Override
public SQLiteDatabase getWritableDatabase ( ) {
SQLiteDatabase db = super . getWritableDatabase ( ) ;
db . execSQL ( " PRAGMA foreign_keys=ON; " ) ;
return db ;
}
2014-02-02 16:05:15 +01:00
public void updateMessage ( Message message ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { message . getUuid ( ) } ;
db . update ( Message . TABLENAME , message . getContentValues ( ) , Message . UUID
+ " =? " , args ) ;
}
2014-02-05 22:33:39 +01:00
2014-05-19 15:15:09 +02:00
public void readRoster ( Roster roster ) {
2014-02-05 22:33:39 +01:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2014-02-10 03:34:00 +01:00
Cursor cursor ;
2014-05-19 15:15:09 +02:00
String args [ ] = { roster . getAccount ( ) . getUuid ( ) } ;
2015-07-03 21:32:46 +02:00
cursor = db . query ( Contact . TABLENAME , null , Contact . ACCOUNT + " =? " , args , null , null , null ) ;
2014-02-05 22:33:39 +01:00
while ( cursor . moveToNext ( ) ) {
2014-05-19 15:15:09 +02:00
roster . initContact ( Contact . fromCursor ( cursor ) ) ;
2014-02-05 22:33:39 +01:00
}
2014-10-08 14:10:37 +02:00
cursor . close ( ) ;
2014-02-05 22:33:39 +01:00
}
2014-07-29 14:42:17 +02:00
2014-11-05 21:55:47 +01:00
public void writeRoster ( final Roster roster ) {
final Account account = roster . getAccount ( ) ;
final SQLiteDatabase db = this . getWritableDatabase ( ) ;
2014-07-29 14:42:17 +02:00
for ( Contact contact : roster . getContacts ( ) ) {
2014-05-19 21:05:17 +02:00
if ( contact . getOption ( Contact . Options . IN_ROSTER ) ) {
db . insert ( Contact . TABLENAME , null , contact . getContentValues ( ) ) ;
} else {
2014-07-29 14:42:17 +02:00
String where = Contact . ACCOUNT + " =? AND " + Contact . JID + " =? " ;
2014-11-05 21:55:47 +01:00
String [ ] whereArgs = { account . getUuid ( ) , contact . getJid ( ) . toString ( ) } ;
2014-05-19 21:05:17 +02:00
db . delete ( Contact . TABLENAME , where , whereArgs ) ;
}
}
account . setRosterVersion ( roster . getVersion ( ) ) ;
updateAccount ( account ) ;
2014-02-05 22:33:39 +01:00
}
2014-02-11 23:55:03 +01:00
public void deleteMessage ( Message message ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { message . getUuid ( ) } ;
db . delete ( Message . TABLENAME , Message . UUID + " =? " , args ) ;
}
2014-05-19 15:15:09 +02:00
2014-04-20 20:48:16 +02:00
public void deleteMessagesInConversation ( Conversation conversation ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { conversation . getUuid ( ) } ;
db . delete ( Message . TABLENAME , Message . CONVERSATION + " =? " , args ) ;
}
2014-02-19 01:35:23 +01:00
2014-04-21 19:51:03 +02:00
public Conversation findConversationByUuid ( String conversationUuid ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
String [ ] selectionArgs = { conversationUuid } ;
2014-05-19 15:15:09 +02:00
Cursor cursor = db . query ( Conversation . TABLENAME , null ,
Conversation . UUID + " =? " , selectionArgs , null , null , null ) ;
2014-04-21 19:51:03 +02:00
if ( cursor . getCount ( ) = = 0 ) {
return null ;
}
cursor . moveToFirst ( ) ;
2014-11-16 00:34:16 +01:00
Conversation conversation = Conversation . fromCursor ( cursor ) ;
cursor . close ( ) ;
return conversation ;
2014-04-21 19:51:03 +02:00
}
public Message findMessageByUuid ( String messageUuid ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
String [ ] selectionArgs = { messageUuid } ;
2014-05-19 15:15:09 +02:00
Cursor cursor = db . query ( Message . TABLENAME , null , Message . UUID + " =? " ,
selectionArgs , null , null , null ) ;
2014-04-21 19:51:03 +02:00
if ( cursor . getCount ( ) = = 0 ) {
return null ;
}
cursor . moveToFirst ( ) ;
2014-11-16 00:34:16 +01:00
Message message = Message . fromCursor ( cursor ) ;
cursor . close ( ) ;
return message ;
2014-04-21 19:51:03 +02:00
}
2014-05-19 15:15:09 +02:00
2014-04-21 19:51:03 +02:00
public Account findAccountByUuid ( String accountUuid ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
String [ ] selectionArgs = { accountUuid } ;
2014-05-19 15:15:09 +02:00
Cursor cursor = db . query ( Account . TABLENAME , null , Account . UUID + " =? " ,
selectionArgs , null , null , null ) ;
2014-04-21 19:51:03 +02:00
if ( cursor . getCount ( ) = = 0 ) {
return null ;
}
cursor . moveToFirst ( ) ;
2014-11-16 00:34:16 +01:00
Account account = Account . fromCursor ( cursor ) ;
cursor . close ( ) ;
return account ;
2014-04-21 19:51:03 +02:00
}
2014-10-30 00:31:44 +01:00
public List < Message > getImageMessages ( Conversation conversation ) {
2014-11-05 21:55:47 +01:00
ArrayList < Message > list = new ArrayList < > ( ) ;
2014-10-30 00:31:44 +01:00
SQLiteDatabase db = this . getReadableDatabase ( ) ;
Cursor cursor ;
String [ ] selectionArgs = { conversation . getUuid ( ) , String . valueOf ( Message . TYPE_IMAGE ) } ;
cursor = db . query ( Message . TABLENAME , null , Message . CONVERSATION
+ " =? AND " + Message . TYPE + " =? " , selectionArgs , null , null , null ) ;
if ( cursor . getCount ( ) > 0 ) {
cursor . moveToLast ( ) ;
do {
Message message = Message . fromCursor ( cursor ) ;
message . setConversation ( conversation ) ;
list . add ( message ) ;
} while ( cursor . moveToPrevious ( ) ) ;
}
2014-11-16 00:34:16 +01:00
cursor . close ( ) ;
2014-10-30 00:31:44 +01:00
return list ;
}
2015-05-29 11:17:26 +02:00
private Cursor getCursorForSession ( Account account , AxolotlAddress contact ) {
final SQLiteDatabase db = this . getReadableDatabase ( ) ;
String [ ] columns = null ;
String [ ] selectionArgs = { account . getUuid ( ) ,
contact . getName ( ) ,
Integer . toString ( contact . getDeviceId ( ) ) } ;
2015-07-28 22:00:54 +02:00
Cursor cursor = db . query ( SQLiteAxolotlStore . SESSION_TABLENAME ,
2015-05-29 11:17:26 +02:00
columns ,
2015-07-28 22:00:54 +02:00
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . NAME + " = ? AND "
+ SQLiteAxolotlStore . DEVICE_ID + " = ? " ,
2015-05-29 11:17:26 +02:00
selectionArgs ,
null , null , null ) ;
return cursor ;
}
public SessionRecord loadSession ( Account account , AxolotlAddress contact ) {
SessionRecord session = null ;
2015-06-26 15:41:02 +02:00
Cursor cursor = getCursorForSession ( account , contact ) ;
2015-05-29 11:17:26 +02:00
if ( cursor . getCount ( ) ! = 0 ) {
cursor . moveToFirst ( ) ;
try {
2015-07-28 22:00:54 +02:00
session = new SessionRecord ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ;
2015-05-29 11:17:26 +02:00
} catch ( IOException e ) {
2015-06-29 13:40:56 +02:00
cursor . close ( ) ;
2015-05-29 11:17:26 +02:00
throw new AssertionError ( e ) ;
}
2015-06-26 15:41:02 +02:00
}
cursor . close ( ) ;
2015-05-29 11:17:26 +02:00
return session ;
}
public List < Integer > getSubDeviceSessions ( Account account , AxolotlAddress contact ) {
final SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-09-05 17:25:46 +02:00
return getSubDeviceSessions ( db , account , contact ) ;
}
private List < Integer > getSubDeviceSessions ( SQLiteDatabase db , Account account , AxolotlAddress contact ) {
List < Integer > devices = new ArrayList < > ( ) ;
2015-07-28 22:00:54 +02:00
String [ ] columns = { SQLiteAxolotlStore . DEVICE_ID } ;
2015-05-29 11:17:26 +02:00
String [ ] selectionArgs = { account . getUuid ( ) ,
contact . getName ( ) } ;
2015-07-28 22:00:54 +02:00
Cursor cursor = db . query ( SQLiteAxolotlStore . SESSION_TABLENAME ,
2015-05-29 11:17:26 +02:00
columns ,
2015-07-28 22:00:54 +02:00
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . NAME + " = ? " ,
2015-05-29 11:17:26 +02:00
selectionArgs ,
null , null , null ) ;
while ( cursor . moveToNext ( ) ) {
devices . add ( cursor . getInt (
2015-07-28 22:00:54 +02:00
cursor . getColumnIndex ( SQLiteAxolotlStore . DEVICE_ID ) ) ) ;
2015-05-29 11:17:26 +02:00
}
cursor . close ( ) ;
return devices ;
}
public boolean containsSession ( Account account , AxolotlAddress contact ) {
Cursor cursor = getCursorForSession ( account , contact ) ;
int count = cursor . getCount ( ) ;
cursor . close ( ) ;
return count ! = 0 ;
}
public void storeSession ( Account account , AxolotlAddress contact , SessionRecord session ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
ContentValues values = new ContentValues ( ) ;
2015-07-28 22:00:54 +02:00
values . put ( SQLiteAxolotlStore . NAME , contact . getName ( ) ) ;
values . put ( SQLiteAxolotlStore . DEVICE_ID , contact . getDeviceId ( ) ) ;
values . put ( SQLiteAxolotlStore . KEY , Base64 . encodeToString ( session . serialize ( ) , Base64 . DEFAULT ) ) ;
values . put ( SQLiteAxolotlStore . ACCOUNT , account . getUuid ( ) ) ;
db . insert ( SQLiteAxolotlStore . SESSION_TABLENAME , null , values ) ;
2015-05-29 11:17:26 +02:00
}
public void deleteSession ( Account account , AxolotlAddress contact ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2015-09-05 17:25:46 +02:00
deleteSession ( db , account , contact ) ;
}
private void deleteSession ( SQLiteDatabase db , Account account , AxolotlAddress contact ) {
2015-05-29 11:17:26 +02:00
String [ ] args = { account . getUuid ( ) ,
contact . getName ( ) ,
Integer . toString ( contact . getDeviceId ( ) ) } ;
2015-07-28 22:00:54 +02:00
db . delete ( SQLiteAxolotlStore . SESSION_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . NAME + " = ? AND "
+ SQLiteAxolotlStore . DEVICE_ID + " = ? " ,
2015-05-29 11:17:26 +02:00
args ) ;
}
public void deleteAllSessions ( Account account , AxolotlAddress contact ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { account . getUuid ( ) , contact . getName ( ) } ;
2015-07-28 22:00:54 +02:00
db . delete ( SQLiteAxolotlStore . SESSION_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " =? AND "
+ SQLiteAxolotlStore . NAME + " = ? " ,
2015-05-29 11:17:26 +02:00
args ) ;
}
private Cursor getCursorForPreKey ( Account account , int preKeyId ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-07-28 22:00:54 +02:00
String [ ] columns = { SQLiteAxolotlStore . KEY } ;
2015-05-29 11:17:26 +02:00
String [ ] selectionArgs = { account . getUuid ( ) , Integer . toString ( preKeyId ) } ;
2015-07-28 22:00:54 +02:00
Cursor cursor = db . query ( SQLiteAxolotlStore . PREKEY_TABLENAME ,
2015-05-29 11:17:26 +02:00
columns ,
2015-07-28 22:00:54 +02:00
SQLiteAxolotlStore . ACCOUNT + " =? AND "
+ SQLiteAxolotlStore . ID + " =? " ,
2015-05-29 11:17:26 +02:00
selectionArgs ,
null , null , null ) ;
return cursor ;
}
public PreKeyRecord loadPreKey ( Account account , int preKeyId ) {
PreKeyRecord record = null ;
Cursor cursor = getCursorForPreKey ( account , preKeyId ) ;
if ( cursor . getCount ( ) ! = 0 ) {
cursor . moveToFirst ( ) ;
try {
2015-07-28 22:00:54 +02:00
record = new PreKeyRecord ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ;
2015-05-29 11:17:26 +02:00
} catch ( IOException e ) {
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 22:00:54 +02:00
values . put ( SQLiteAxolotlStore . ID , record . getId ( ) ) ;
values . put ( SQLiteAxolotlStore . KEY , Base64 . encodeToString ( record . serialize ( ) , Base64 . DEFAULT ) ) ;
values . put ( SQLiteAxolotlStore . ACCOUNT , account . getUuid ( ) ) ;
db . insert ( SQLiteAxolotlStore . PREKEY_TABLENAME , null , values ) ;
2015-05-29 11:17:26 +02:00
}
public void deletePreKey ( Account account , int preKeyId ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { account . getUuid ( ) , Integer . toString ( preKeyId ) } ;
2015-07-28 22:00:54 +02:00
db . delete ( SQLiteAxolotlStore . PREKEY_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " =? AND "
+ SQLiteAxolotlStore . ID + " =? " ,
2015-05-29 11:17:26 +02:00
args ) ;
}
private Cursor getCursorForSignedPreKey ( Account account , int signedPreKeyId ) {
SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-07-28 22:00:54 +02:00
String [ ] columns = { SQLiteAxolotlStore . KEY } ;
2015-05-29 11:17:26 +02:00
String [ ] selectionArgs = { account . getUuid ( ) , Integer . toString ( signedPreKeyId ) } ;
2015-07-28 22:00:54 +02:00
Cursor cursor = db . query ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
2015-05-29 11:17:26 +02:00
columns ,
2015-07-28 22:00:54 +02:00
SQLiteAxolotlStore . ACCOUNT + " =? AND " + SQLiteAxolotlStore . ID + " =? " ,
2015-05-29 11:17:26 +02:00
selectionArgs ,
null , null , null ) ;
return cursor ;
}
public SignedPreKeyRecord loadSignedPreKey ( Account account , int signedPreKeyId ) {
SignedPreKeyRecord record = null ;
2015-06-25 16:56:34 +02:00
Cursor cursor = getCursorForSignedPreKey ( account , signedPreKeyId ) ;
2015-05-29 11:17:26 +02:00
if ( cursor . getCount ( ) ! = 0 ) {
cursor . moveToFirst ( ) ;
try {
2015-07-28 22:00:54 +02:00
record = new SignedPreKeyRecord ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ;
2015-05-29 11:17:26 +02:00
} catch ( IOException e ) {
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 22:00:54 +02:00
String [ ] columns = { SQLiteAxolotlStore . KEY } ;
2015-05-29 11:17:26 +02:00
String [ ] selectionArgs = { account . getUuid ( ) } ;
2015-07-28 22:00:54 +02:00
Cursor cursor = db . query ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
2015-05-29 11:17:26 +02:00
columns ,
2015-07-28 22:00:54 +02:00
SQLiteAxolotlStore . ACCOUNT + " =? " ,
2015-05-29 11:17:26 +02:00
selectionArgs ,
null , null , null ) ;
while ( cursor . moveToNext ( ) ) {
try {
2015-07-28 22:00:54 +02:00
prekeys . add ( new SignedPreKeyRecord ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ) ;
2015-05-29 11:17:26 +02:00
} catch ( IOException ignored ) {
}
}
2015-06-29 13:40:56 +02:00
cursor . close ( ) ;
2015-05-29 11:17:26 +02:00
return prekeys ;
}
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 22:00:54 +02:00
values . put ( SQLiteAxolotlStore . ID , record . getId ( ) ) ;
values . put ( SQLiteAxolotlStore . KEY , Base64 . encodeToString ( record . serialize ( ) , Base64 . DEFAULT ) ) ;
values . put ( SQLiteAxolotlStore . ACCOUNT , account . getUuid ( ) ) ;
db . insert ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME , null , values ) ;
2015-05-29 11:17:26 +02:00
}
public void deleteSignedPreKey ( Account account , int signedPreKeyId ) {
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] args = { account . getUuid ( ) , Integer . toString ( signedPreKeyId ) } ;
2015-07-28 22:00:54 +02:00
db . delete ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " =? AND "
+ SQLiteAxolotlStore . ID + " =? " ,
2015-05-29 11:17:26 +02:00
args ) ;
}
2015-06-29 13:53:39 +02:00
private Cursor getIdentityKeyCursor ( Account account , String name , boolean own ) {
2015-09-05 17:25:46 +02:00
final SQLiteDatabase db = this . getReadableDatabase ( ) ;
return getIdentityKeyCursor ( db , account , name , own ) ;
2015-07-09 14:23:17 +02:00
}
2015-09-05 17:25:46 +02:00
private Cursor getIdentityKeyCursor ( SQLiteDatabase db , Account account , String name , boolean own ) {
return getIdentityKeyCursor ( db , account , name , own , null ) ;
2015-07-15 16:32:42 +02:00
}
2015-09-05 17:25:46 +02:00
private Cursor getIdentityKeyCursor ( Account account , String fingerprint ) {
2015-06-29 13:53:39 +02:00
final SQLiteDatabase db = this . getReadableDatabase ( ) ;
2015-09-05 17:25:46 +02: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 ) {
2015-07-28 22:00:54 +02:00
String [ ] columns = { SQLiteAxolotlStore . TRUSTED ,
SQLiteAxolotlStore . KEY } ;
2015-07-09 14:23:17 +02:00
ArrayList < String > selectionArgs = new ArrayList < > ( 4 ) ;
selectionArgs . add ( account . getUuid ( ) ) ;
2015-07-28 22:00:54 +02:00
String selectionString = SQLiteAxolotlStore . ACCOUNT + " = ? " ;
2015-07-15 16:32:42 +02:00
if ( name ! = null ) {
selectionArgs . add ( name ) ;
2015-07-28 22:00:54 +02:00
selectionString + = " AND " + SQLiteAxolotlStore . NAME + " = ? " ;
2015-07-15 16:32:42 +02:00
}
2015-07-09 14:23:17 +02:00
if ( fingerprint ! = null ) {
selectionArgs . add ( fingerprint ) ;
2015-07-28 22:00:54 +02:00
selectionString + = " AND " + SQLiteAxolotlStore . FINGERPRINT + " = ? " ;
2015-07-15 16:32:42 +02:00
}
if ( own ! = null ) {
selectionArgs . add ( own ? " 1 " : " 0 " ) ;
2015-07-28 22:00:54 +02:00
selectionString + = " AND " + SQLiteAxolotlStore . OWN + " = ? " ;
2015-07-09 14:23:17 +02:00
}
2015-07-28 22:00:54 +02:00
Cursor cursor = db . query ( SQLiteAxolotlStore . IDENTITIES_TABLENAME ,
2015-06-29 13:53:39 +02:00
columns ,
2015-07-09 14:23:17 +02:00
selectionString ,
selectionArgs . toArray ( new String [ selectionArgs . size ( ) ] ) ,
2015-06-29 13:53:39 +02:00
null , null , null ) ;
return cursor ;
}
2015-09-05 17:25:46 +02:00
public IdentityKeyPair loadOwnIdentityKeyPair ( Account account ) {
SQLiteDatabase db = getReadableDatabase ( ) ;
return loadOwnIdentityKeyPair ( db , account ) ;
}
private IdentityKeyPair loadOwnIdentityKeyPair ( SQLiteDatabase db , Account account ) {
String name = account . getJid ( ) . toBareJid ( ) . toString ( ) ;
2015-06-29 13:53:39 +02:00
IdentityKeyPair identityKeyPair = null ;
2015-09-05 17:25:46 +02:00
Cursor cursor = getIdentityKeyCursor ( db , account , name , true ) ;
2015-06-29 13:53:39 +02:00
if ( cursor . getCount ( ) ! = 0 ) {
cursor . moveToFirst ( ) ;
try {
2015-07-28 22:00:54 +02:00
identityKeyPair = new IdentityKeyPair ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) ) ;
2015-06-29 13:53:39 +02:00
} catch ( InvalidKeyException e ) {
2015-07-08 17:44:24 +02:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Encountered invalid IdentityKey in database for account " + account . getJid ( ) . toBareJid ( ) + " , address: " + name ) ;
2015-06-29 13:53:39 +02:00
}
}
cursor . close ( ) ;
return identityKeyPair ;
}
public Set < IdentityKey > loadIdentityKeys ( Account account , String name ) {
2015-07-19 18:36:28 +02:00
return loadIdentityKeys ( account , name , null ) ;
}
2015-08-01 18:27:52 +02:00
public Set < IdentityKey > loadIdentityKeys ( Account account , String name , XmppAxolotlSession . Trust trust ) {
2015-06-29 13:53:39 +02:00
Set < IdentityKey > identityKeys = new HashSet < > ( ) ;
Cursor cursor = getIdentityKeyCursor ( account , name , false ) ;
while ( cursor . moveToNext ( ) ) {
2015-07-19 18:36:28 +02:00
if ( trust ! = null & &
2015-07-28 22:00:54 +02:00
cursor . getInt ( cursor . getColumnIndex ( SQLiteAxolotlStore . TRUSTED ) )
2015-07-21 01:52:22 +02:00
! = trust . getCode ( ) ) {
2015-07-19 18:36:28 +02:00
continue ;
}
2015-06-29 13:53:39 +02:00
try {
2015-07-28 22:00:54 +02:00
identityKeys . add ( new IdentityKey ( Base64 . decode ( cursor . getString ( cursor . getColumnIndex ( SQLiteAxolotlStore . KEY ) ) , Base64 . DEFAULT ) , 0 ) ) ;
2015-06-29 13:53:39 +02:00
} catch ( InvalidKeyException e ) {
2015-07-08 17:44:24 +02:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " Encountered invalid IdentityKey in database for account " + account . getJid ( ) . toBareJid ( ) + " , address: " + name ) ;
2015-06-29 13:53:39 +02:00
}
}
cursor . close ( ) ;
return identityKeys ;
}
2015-07-20 14:56:41 +02:00
public long numTrustedKeys ( Account account , String name ) {
SQLiteDatabase db = getReadableDatabase ( ) ;
String [ ] args = {
account . getUuid ( ) ,
2015-07-20 22:02:54 +02:00
name ,
2015-08-01 18:27:52 +02:00
String . valueOf ( XmppAxolotlSession . Trust . TRUSTED . getCode ( ) )
2015-07-20 14:56:41 +02:00
} ;
2015-07-28 22:00:54 +02:00
return DatabaseUtils . queryNumEntries ( db , SQLiteAxolotlStore . IDENTITIES_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? "
+ " AND " + SQLiteAxolotlStore . NAME + " = ? "
+ " AND " + SQLiteAxolotlStore . TRUSTED + " = ? " ,
2015-07-20 14:56:41 +02:00
args
) ;
}
2015-07-09 14:23:17 +02:00
private void storeIdentityKey ( Account account , String name , boolean own , String fingerprint , String base64Serialized ) {
2015-08-01 18:27:52 +02:00
storeIdentityKey ( account , name , own , fingerprint , base64Serialized , XmppAxolotlSession . Trust . UNDECIDED ) ;
2015-07-15 16:32:42 +02:00
}
2015-08-01 18:27:52 +02:00
private void storeIdentityKey ( Account account , String name , boolean own , String fingerprint , String base64Serialized , XmppAxolotlSession . Trust trusted ) {
2015-06-29 13:53:39 +02:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
ContentValues values = new ContentValues ( ) ;
2015-07-28 22:00:54 +02: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 ) ;
values . put ( SQLiteAxolotlStore . TRUSTED , trusted . getCode ( ) ) ;
db . insert ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , null , values ) ;
2015-06-29 13:53:39 +02:00
}
2015-08-01 18:27:52 +02:00
public XmppAxolotlSession . Trust isIdentityKeyTrusted ( Account account , String fingerprint ) {
2015-07-15 16:32:42 +02:00
Cursor cursor = getIdentityKeyCursor ( account , fingerprint ) ;
2015-08-01 18:27:52 +02:00
XmppAxolotlSession . Trust trust = null ;
2015-07-09 14:23:17 +02:00
if ( cursor . getCount ( ) > 0 ) {
cursor . moveToFirst ( ) ;
2015-07-28 22:00:54 +02:00
int trustValue = cursor . getInt ( cursor . getColumnIndex ( SQLiteAxolotlStore . TRUSTED ) ) ;
2015-08-01 18:27:52 +02:00
trust = XmppAxolotlSession . Trust . fromCode ( trustValue ) ;
2015-07-09 14:23:17 +02:00
}
cursor . close ( ) ;
return trust ;
}
2015-08-01 18:27:52 +02:00
public boolean setIdentityKeyTrust ( Account account , String fingerprint , XmppAxolotlSession . Trust trust ) {
2015-07-09 14:23:17 +02:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
2015-09-05 17:25:46 +02:00
return setIdentityKeyTrust ( db , account , fingerprint , trust ) ;
}
private boolean setIdentityKeyTrust ( SQLiteDatabase db , Account account , String fingerprint , XmppAxolotlSession . Trust trust ) {
2015-07-09 14:23:17 +02:00
String [ ] selectionArgs = {
account . getUuid ( ) ,
fingerprint
} ;
ContentValues values = new ContentValues ( ) ;
2015-07-28 22:00:54 +02:00
values . put ( SQLiteAxolotlStore . TRUSTED , trust . getCode ( ) ) ;
int rows = db . update ( SQLiteAxolotlStore . IDENTITIES_TABLENAME , values ,
SQLiteAxolotlStore . ACCOUNT + " = ? AND "
+ SQLiteAxolotlStore . FINGERPRINT + " = ? " ,
2015-07-09 14:23:17 +02:00
selectionArgs ) ;
return rows = = 1 ;
}
2015-06-29 13:53:39 +02:00
public void storeIdentityKey ( Account account , String name , IdentityKey identityKey ) {
2015-07-09 14:23:17 +02:00
storeIdentityKey ( account , name , false , identityKey . getFingerprint ( ) . replaceAll ( " \\ s " , " " ) , Base64 . encodeToString ( identityKey . serialize ( ) , Base64 . DEFAULT ) ) ;
2015-06-29 13:53:39 +02:00
}
2015-09-05 17:25:46 +02:00
public void storeOwnIdentityKeyPair ( Account account , IdentityKeyPair identityKeyPair ) {
storeIdentityKey ( account , account . getJid ( ) . toBareJid ( ) . toString ( ) , true , identityKeyPair . getPublicKey ( ) . getFingerprint ( ) . replaceAll ( " \\ s " , " " ) , Base64 . encodeToString ( identityKeyPair . serialize ( ) , Base64 . DEFAULT ) , XmppAxolotlSession . Trust . TRUSTED ) ;
2015-06-29 13:53:39 +02:00
}
2015-07-07 19:30:08 +02:00
public void recreateAxolotlDb ( ) {
2015-07-20 13:15:49 +02:00
recreateAxolotlDb ( getWritableDatabase ( ) ) ;
}
public void recreateAxolotlDb ( SQLiteDatabase db ) {
2015-07-08 17:44:24 +02:00
Log . d ( Config . LOGTAG , AxolotlService . LOGPREFIX + " : " + " >>> (RE)CREATING AXOLOTL DATABASE <<< " ) ;
2015-07-28 22:00:54 +02:00
db . execSQL ( " DROP TABLE IF EXISTS " + SQLiteAxolotlStore . SESSION_TABLENAME ) ;
2015-07-07 19:30:08 +02:00
db . execSQL ( CREATE_SESSIONS_STATEMENT ) ;
2015-07-28 22:00:54 +02:00
db . execSQL ( " DROP TABLE IF EXISTS " + SQLiteAxolotlStore . PREKEY_TABLENAME ) ;
2015-07-07 19:30:08 +02:00
db . execSQL ( CREATE_PREKEYS_STATEMENT ) ;
2015-07-28 22:00:54 +02:00
db . execSQL ( " DROP TABLE IF EXISTS " + SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ) ;
2015-07-07 19:30:08 +02:00
db . execSQL ( CREATE_SIGNED_PREKEYS_STATEMENT ) ;
2015-07-28 22:00:54 +02:00
db . execSQL ( " DROP TABLE IF EXISTS " + SQLiteAxolotlStore . IDENTITIES_TABLENAME ) ;
2015-07-07 19:30:08 +02:00
db . execSQL ( CREATE_IDENTITIES_STATEMENT ) ;
}
2015-07-07 19:36:22 +02:00
public void wipeAxolotlDb ( Account account ) {
String accountName = account . getUuid ( ) ;
2015-07-08 17:44:24 +02:00
Log . d ( Config . LOGTAG , AxolotlService . getLogprefix ( account ) + " >>> WIPING AXOLOTL DATABASE FOR ACCOUNT " + accountName + " <<< " ) ;
2015-07-07 19:36:22 +02:00
SQLiteDatabase db = this . getWritableDatabase ( ) ;
String [ ] deleteArgs = {
accountName
} ;
2015-07-28 22:00:54 +02:00
db . delete ( SQLiteAxolotlStore . SESSION_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
2015-07-07 19:36:22 +02:00
deleteArgs ) ;
2015-07-28 22:00:54 +02:00
db . delete ( SQLiteAxolotlStore . PREKEY_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
2015-07-07 19:36:22 +02:00
deleteArgs ) ;
2015-07-28 22:00:54 +02:00
db . delete ( SQLiteAxolotlStore . SIGNED_PREKEY_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
2015-07-07 19:36:22 +02:00
deleteArgs ) ;
2015-07-28 22:00:54 +02:00
db . delete ( SQLiteAxolotlStore . IDENTITIES_TABLENAME ,
SQLiteAxolotlStore . ACCOUNT + " = ? " ,
2015-07-07 19:36:22 +02:00
deleteArgs ) ;
}
2014-01-24 23:58:51 +01:00
}