2020-05-12 03:46:11 +02:00
|
|
|
package org.thoughtcrime.securesms.loki.database
|
2019-07-22 01:38:12 +02:00
|
|
|
|
|
|
|
import android.content.ContentValues
|
|
|
|
import android.content.Context
|
2019-10-10 02:38:43 +02:00
|
|
|
import android.database.Cursor
|
2020-05-21 03:00:54 +02:00
|
|
|
import android.util.Log
|
2019-07-22 04:09:34 +02:00
|
|
|
import org.thoughtcrime.securesms.database.Address
|
2019-07-22 01:38:12 +02:00
|
|
|
import org.thoughtcrime.securesms.database.Database
|
|
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory
|
|
|
|
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
|
2020-05-11 08:19:26 +02:00
|
|
|
import org.thoughtcrime.securesms.loki.utilities.*
|
2019-07-22 04:09:34 +02:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient
|
2019-12-06 03:00:08 +01:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
2020-02-14 01:18:23 +01:00
|
|
|
import org.whispersystems.libsignal.loki.LokiSessionResetStatus
|
2019-10-10 01:53:17 +02:00
|
|
|
import org.whispersystems.signalservice.internal.util.JsonUtil
|
2020-05-07 09:59:41 +02:00
|
|
|
import org.whispersystems.signalservice.loki.api.opengroups.LokiPublicChat
|
|
|
|
import org.whispersystems.signalservice.loki.database.LokiThreadDatabaseProtocol
|
|
|
|
import org.whispersystems.signalservice.loki.protocol.todo.LokiThreadFriendRequestStatus
|
2019-12-06 06:33:17 +01:00
|
|
|
import org.whispersystems.signalservice.loki.utilities.PublicKeyValidation
|
2019-07-22 01:38:12 +02:00
|
|
|
|
|
|
|
class LokiThreadDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), LokiThreadDatabaseProtocol {
|
|
|
|
var delegate: LokiThreadDatabaseDelegate? = null
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
private val friendRequestTableName = "loki_thread_friend_request_database"
|
2019-07-22 06:25:59 +02:00
|
|
|
private val sessionResetTableName = "loki_thread_session_reset_database"
|
2020-02-14 01:18:23 +01:00
|
|
|
val publicChatTableName = "loki_public_chat_database"
|
|
|
|
val threadID = "thread_id"
|
2019-07-22 01:38:12 +02:00
|
|
|
private val friendRequestStatus = "friend_request_status"
|
2019-07-22 06:25:59 +02:00
|
|
|
private val sessionResetStatus = "session_reset_status"
|
2020-02-14 01:18:23 +01:00
|
|
|
val publicChat = "public_chat"
|
2019-07-22 01:38:12 +02:00
|
|
|
@JvmStatic val createFriendRequestTableCommand = "CREATE TABLE $friendRequestTableName ($threadID INTEGER PRIMARY KEY, $friendRequestStatus INTEGER DEFAULT 0);"
|
2019-07-22 06:25:59 +02:00
|
|
|
@JvmStatic val createSessionResetTableCommand = "CREATE TABLE $sessionResetTableName ($threadID INTEGER PRIMARY KEY, $sessionResetStatus INTEGER DEFAULT 0);"
|
2019-10-15 07:06:38 +02:00
|
|
|
@JvmStatic val createPublicChatTableCommand = "CREATE TABLE $publicChatTableName ($threadID INTEGER PRIMARY KEY, $publicChat TEXT);"
|
2019-07-22 01:38:12 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 08:48:54 +02:00
|
|
|
override fun getThreadID(hexEncodedPublicKey: String): Long {
|
|
|
|
val address = Address.fromSerialized(hexEncodedPublicKey)
|
2019-07-22 04:09:34 +02:00
|
|
|
val recipient = Recipient.from(context, address, false)
|
|
|
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
|
|
|
|
}
|
|
|
|
|
2019-10-10 01:53:17 +02:00
|
|
|
fun getThreadID(messageID: Long): Long {
|
2019-07-22 01:38:12 +02:00
|
|
|
return DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageID)
|
|
|
|
}
|
|
|
|
|
|
|
|
fun getFriendRequestStatus(threadID: Long): LokiThreadFriendRequestStatus {
|
2019-11-04 01:17:34 +01:00
|
|
|
if (threadID < 0) { return LokiThreadFriendRequestStatus.NONE }
|
2019-12-12 06:07:13 +01:00
|
|
|
val recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID)
|
|
|
|
if (recipient != null && recipient.isGroupRecipient) { return LokiThreadFriendRequestStatus.FRIENDS; }
|
2019-07-22 01:38:12 +02:00
|
|
|
val database = databaseHelper.readableDatabase
|
|
|
|
val result = database.get(friendRequestTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor ->
|
|
|
|
cursor.getInt(friendRequestStatus)
|
|
|
|
}
|
|
|
|
return if (result != null) {
|
|
|
|
LokiThreadFriendRequestStatus.values().first { it.rawValue == result }
|
|
|
|
} else {
|
|
|
|
LokiThreadFriendRequestStatus.NONE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun setFriendRequestStatus(threadID: Long, friendRequestStatus: LokiThreadFriendRequestStatus) {
|
2019-11-04 01:17:34 +01:00
|
|
|
if (threadID < 0) { return }
|
2020-05-21 03:00:54 +02:00
|
|
|
Log.d("Loki", "Setting FR status for thread with ID $threadID to $friendRequestStatus.")
|
2019-07-22 01:38:12 +02:00
|
|
|
val database = databaseHelper.writableDatabase
|
|
|
|
val contentValues = ContentValues(2)
|
|
|
|
contentValues.put(Companion.threadID, threadID)
|
|
|
|
contentValues.put(Companion.friendRequestStatus, friendRequestStatus.rawValue)
|
|
|
|
database.insertOrUpdate(friendRequestTableName, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
|
|
|
|
notifyConversationListListeners()
|
|
|
|
notifyConversationListeners(threadID)
|
|
|
|
delegate?.handleThreadFriendRequestStatusChanged(threadID)
|
|
|
|
}
|
|
|
|
|
|
|
|
fun hasPendingFriendRequest(threadID: Long): Boolean {
|
|
|
|
val friendRequestStatus = getFriendRequestStatus(threadID)
|
|
|
|
return friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENDING || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT
|
|
|
|
|| friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED
|
|
|
|
}
|
|
|
|
|
2020-02-14 01:18:23 +01:00
|
|
|
fun getSessionResetStatus(hexEncodedPublicKey: String): LokiSessionResetStatus {
|
|
|
|
val threadID = getThreadID(hexEncodedPublicKey)
|
2019-07-22 01:38:12 +02:00
|
|
|
val database = databaseHelper.readableDatabase
|
|
|
|
val result = database.get(sessionResetTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor ->
|
2019-07-22 06:25:59 +02:00
|
|
|
cursor.getInt(sessionResetStatus)
|
2019-07-22 01:38:12 +02:00
|
|
|
}
|
|
|
|
return if (result != null) {
|
2020-02-14 01:18:23 +01:00
|
|
|
LokiSessionResetStatus.values().first { it.rawValue == result }
|
2019-07-22 01:38:12 +02:00
|
|
|
} else {
|
2020-02-14 01:18:23 +01:00
|
|
|
LokiSessionResetStatus.NONE
|
2019-07-22 01:38:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 01:18:23 +01:00
|
|
|
fun setSessionResetStatus(hexEncodedPublicKey: String, sessionResetStatus: LokiSessionResetStatus) {
|
|
|
|
val threadID = getThreadID(hexEncodedPublicKey)
|
2019-07-22 01:38:12 +02:00
|
|
|
val database = databaseHelper.writableDatabase
|
|
|
|
val contentValues = ContentValues(2)
|
|
|
|
contentValues.put(Companion.threadID, threadID)
|
2019-07-22 06:25:59 +02:00
|
|
|
contentValues.put(Companion.sessionResetStatus, sessionResetStatus.rawValue)
|
2019-07-22 01:38:12 +02:00
|
|
|
database.insertOrUpdate(sessionResetTableName, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
|
|
|
|
notifyConversationListListeners()
|
|
|
|
notifyConversationListeners(threadID)
|
|
|
|
}
|
2019-10-10 01:53:17 +02:00
|
|
|
|
2019-10-15 04:39:17 +02:00
|
|
|
fun getAllPublicChats(): Map<Long, LokiPublicChat> {
|
2019-10-10 02:38:43 +02:00
|
|
|
val database = databaseHelper.readableDatabase
|
|
|
|
var cursor: Cursor? = null
|
2019-10-15 05:32:23 +02:00
|
|
|
val result = mutableMapOf<Long, LokiPublicChat>()
|
2019-10-10 02:38:43 +02:00
|
|
|
try {
|
2019-10-15 05:32:23 +02:00
|
|
|
cursor = database.rawQuery("select * from $publicChatTableName", null)
|
2019-10-10 02:38:43 +02:00
|
|
|
while (cursor != null && cursor.moveToNext()) {
|
2019-10-15 05:32:23 +02:00
|
|
|
val threadID = cursor.getLong(threadID)
|
|
|
|
val string = cursor.getString(publicChat)
|
|
|
|
val publicChat = LokiPublicChat.fromJSON(string)
|
|
|
|
if (publicChat != null) { result[threadID] = publicChat }
|
2019-10-10 02:38:43 +02:00
|
|
|
}
|
|
|
|
} catch (e: Exception) {
|
2019-10-15 05:32:23 +02:00
|
|
|
// Do nothing
|
2019-10-10 02:38:43 +02:00
|
|
|
} finally {
|
|
|
|
cursor?.close()
|
|
|
|
}
|
2019-10-15 05:32:23 +02:00
|
|
|
return result
|
2019-10-10 02:38:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-15 04:39:17 +02:00
|
|
|
fun getAllPublicChatServers(): Set<String> {
|
2019-10-15 05:32:23 +02:00
|
|
|
return getAllPublicChats().values.fold(setOf()) { set, chat -> set.plus(chat.server) }
|
2019-10-10 02:38:43 +02:00
|
|
|
}
|
|
|
|
|
2019-10-15 04:39:17 +02:00
|
|
|
override fun getPublicChat(threadID: Long): LokiPublicChat? {
|
2019-10-10 02:38:43 +02:00
|
|
|
if (threadID < 0) { return null }
|
2019-10-10 01:53:17 +02:00
|
|
|
val database = databaseHelper.readableDatabase
|
2019-10-15 05:32:23 +02:00
|
|
|
return database.get(publicChatTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() )) { cursor ->
|
|
|
|
val publicChatAsJSON = cursor.getString(publicChat)
|
|
|
|
LokiPublicChat.fromJSON(publicChatAsJSON)
|
2019-10-10 01:53:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-15 05:32:23 +02:00
|
|
|
override fun setPublicChat(publicChat: LokiPublicChat, threadID: Long) {
|
2019-10-10 02:38:43 +02:00
|
|
|
if (threadID < 0) { return }
|
2019-10-10 01:53:17 +02:00
|
|
|
val database = databaseHelper.writableDatabase
|
|
|
|
val contentValues = ContentValues(2)
|
|
|
|
contentValues.put(Companion.threadID, threadID)
|
2019-10-15 05:32:23 +02:00
|
|
|
contentValues.put(Companion.publicChat, JsonUtil.toJson(publicChat.toJSON()))
|
|
|
|
database.insertOrUpdate(publicChatTableName, contentValues, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
|
2019-10-10 01:53:17 +02:00
|
|
|
}
|
|
|
|
|
2019-10-15 04:39:17 +02:00
|
|
|
override fun removePublicChat(threadID: Long) {
|
2019-10-15 05:32:23 +02:00
|
|
|
databaseHelper.writableDatabase.delete(publicChatTableName, "${Companion.threadID} = ?", arrayOf( threadID.toString() ))
|
2019-10-10 01:53:17 +02:00
|
|
|
}
|
2019-12-06 03:00:08 +01:00
|
|
|
|
|
|
|
fun addSessionRestoreDevice(threadID: Long, hexEncodedPublicKey: String) {
|
|
|
|
val devices = getSessionRestoreDevices(threadID).toMutableSet()
|
|
|
|
if (devices.add(hexEncodedPublicKey)) {
|
|
|
|
TextSecurePreferences.setStringPreference(context, "session_restore_devices_$threadID", devices.joinToString(","))
|
|
|
|
delegate?.handleSessionRestoreDevicesChanged(threadID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fun getSessionRestoreDevices(threadID: Long): Set<String> {
|
2019-12-06 06:33:17 +01:00
|
|
|
return TextSecurePreferences.getStringPreference(context, "session_restore_devices_$threadID", "")
|
2020-01-28 00:52:06 +01:00
|
|
|
.split(",")
|
|
|
|
.filter { PublicKeyValidation.isValid(it) }
|
|
|
|
.toSet()
|
2019-12-06 03:00:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fun removeAllSessionRestoreDevices(threadID: Long) {
|
|
|
|
TextSecurePreferences.setStringPreference(context, "session_restore_devices_$threadID", "")
|
|
|
|
delegate?.handleSessionRestoreDevicesChanged(threadID)
|
|
|
|
}
|
2019-07-22 01:38:12 +02:00
|
|
|
}
|