mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-22 03:48:26 +00:00
add thread related classes
This commit is contained in:
parent
fea965e37f
commit
c759f25577
@ -1,31 +0,0 @@
|
|||||||
package org.session.libsession.messaging
|
|
||||||
|
|
||||||
import org.session.libsession.database.MessageDataProvider
|
|
||||||
import org.session.libsignal.libsignal.loki.SessionResetProtocol
|
|
||||||
import org.session.libsignal.libsignal.state.*
|
|
||||||
import org.session.libsignal.metadata.certificate.CertificateValidator
|
|
||||||
import org.session.libsignal.service.loki.protocol.closedgroups.SharedSenderKeysDatabaseProtocol
|
|
||||||
|
|
||||||
class Configuration(
|
|
||||||
val storage: StorageProtocol,
|
|
||||||
val signalStorage: SignalProtocolStore,
|
|
||||||
val sskDatabase: SharedSenderKeysDatabaseProtocol,
|
|
||||||
val messageDataProvider: MessageDataProvider,
|
|
||||||
val sessionResetImp: SessionResetProtocol,
|
|
||||||
val certificateValidator: CertificateValidator)
|
|
||||||
{
|
|
||||||
companion object {
|
|
||||||
lateinit var shared: Configuration
|
|
||||||
|
|
||||||
fun configure(storage: StorageProtocol,
|
|
||||||
signalStorage: SignalProtocolStore,
|
|
||||||
sskDatabase: SharedSenderKeysDatabaseProtocol,
|
|
||||||
messageDataProvider: MessageDataProvider,
|
|
||||||
sessionResetImp: SessionResetProtocol,
|
|
||||||
certificateValidator: CertificateValidator
|
|
||||||
) {
|
|
||||||
if (Companion::shared.isInitialized) { return }
|
|
||||||
shared = Configuration(storage, signalStorage, sskDatabase, messageDataProvider, sessionResetImp, certificateValidator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,181 @@
|
|||||||
|
package org.session.libsession.messaging.threads
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
import android.util.Pair
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import org.session.libsession.utilities.DelimiterUtil.escape
|
||||||
|
import org.session.libsession.utilities.DelimiterUtil.split
|
||||||
|
import org.session.libsession.utilities.DelimiterUtil.unescape
|
||||||
|
import org.session.libsession.utilities.GroupUtil
|
||||||
|
import org.session.libsession.utilities.NumberUtil.isValidEmail
|
||||||
|
import org.session.libsignal.libsignal.util.guava.Optional
|
||||||
|
import org.session.libsignal.service.internal.util.Util
|
||||||
|
import java.lang.AssertionError
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
import java.util.regex.Matcher
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
class Address private constructor(address: String) : Parcelable, Comparable<Address?> {
|
||||||
|
private val address: String = address.toLowerCase()
|
||||||
|
|
||||||
|
constructor(`in`: Parcel) : this(`in`.readString()!!) {}
|
||||||
|
|
||||||
|
val isGroup: Boolean
|
||||||
|
get() = GroupUtil.isEncodedGroup(address)
|
||||||
|
val isClosedGroup: Boolean
|
||||||
|
get() = GroupUtil.isClosedGroup(address)
|
||||||
|
val isOpenGroup: Boolean
|
||||||
|
get() = GroupUtil.isOpenGroup(address)
|
||||||
|
val isMmsGroup: Boolean
|
||||||
|
get() = GroupUtil.isMmsGroup(address)
|
||||||
|
val isContact: Boolean
|
||||||
|
get() = !isGroup
|
||||||
|
|
||||||
|
fun contactIdentifier(): String {
|
||||||
|
if (!isContact && !isOpenGroup) {
|
||||||
|
if (isGroup) throw AssertionError("Not e164, is group")
|
||||||
|
throw AssertionError("Not e164, unknown")
|
||||||
|
}
|
||||||
|
return address
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return address
|
||||||
|
}
|
||||||
|
|
||||||
|
fun serialize(): String {
|
||||||
|
return address
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
return if (other == null || other !is Address) false else address == other.address
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return address.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun describeContents(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
|
dest.writeString(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun compareTo(other: Address?): Int {
|
||||||
|
return address.compareTo(other?.address!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
class ExternalAddressFormatter internal constructor(localCountryCode: String, countryCode: Boolean) {
|
||||||
|
private val localNumber: Optional<PhoneNumber>
|
||||||
|
private val localCountryCode: String
|
||||||
|
private val ALPHA_PATTERN = Pattern.compile("[a-zA-Z]")
|
||||||
|
fun format(number: String?): String {
|
||||||
|
return number ?: "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseAreaCode(e164Number: String, countryCode: Int): String? {
|
||||||
|
when (countryCode) {
|
||||||
|
1 -> return e164Number.substring(2, 5)
|
||||||
|
55 -> return e164Number.substring(3, 5)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun applyAreaCodeRules(localNumber: Optional<PhoneNumber>, testNumber: String): String {
|
||||||
|
if (!localNumber.isPresent || !localNumber.get().areaCode.isPresent) {
|
||||||
|
return testNumber
|
||||||
|
}
|
||||||
|
val matcher: Matcher
|
||||||
|
when (localNumber.get().countryCode) {
|
||||||
|
1 -> {
|
||||||
|
matcher = US_NO_AREACODE.matcher(testNumber)
|
||||||
|
if (matcher.matches()) {
|
||||||
|
return localNumber.get().areaCode.toString() + matcher.group()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
55 -> {
|
||||||
|
matcher = BR_NO_AREACODE.matcher(testNumber)
|
||||||
|
if (matcher.matches()) {
|
||||||
|
return localNumber.get().areaCode.toString() + matcher.group()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return testNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PhoneNumber internal constructor(val e164Number: String, val countryCode: Int, areaCode: String?) {
|
||||||
|
val areaCode: Optional<String?>
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.areaCode = Optional.fromNullable(areaCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = ExternalAddressFormatter::class.java.simpleName
|
||||||
|
private val SHORT_COUNTRIES: HashSet<String?> = object : HashSet<String?>() {
|
||||||
|
init {
|
||||||
|
add("NU")
|
||||||
|
add("TK")
|
||||||
|
add("NC")
|
||||||
|
add("AC")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val US_NO_AREACODE = Pattern.compile("^(\\d{7})$")
|
||||||
|
private val BR_NO_AREACODE = Pattern.compile("^(9?\\d{8})$")
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
localNumber = Optional.absent()
|
||||||
|
this.localCountryCode = localCountryCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val CREATOR: Parcelable.Creator<Address?> = object : Parcelable.Creator<Address?> {
|
||||||
|
override fun createFromParcel(`in`: Parcel): Address {
|
||||||
|
return Address(`in`)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(size: Int): Array<Address?> {
|
||||||
|
return arrayOfNulls(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val UNKNOWN = Address("Unknown")
|
||||||
|
private val TAG = Address::class.java.simpleName
|
||||||
|
private val cachedFormatter = AtomicReference<Pair<String, ExternalAddressFormatter>>()
|
||||||
|
fun fromSerialized(serialized: String): Address {
|
||||||
|
return Address(serialized)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fromExternal(context: Context, external: String?): Address {
|
||||||
|
return fromSerialized(external!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fromSerializedList(serialized: String, delimiter: Char): List<Address> {
|
||||||
|
val escapedAddresses = split(serialized, delimiter)
|
||||||
|
val addresses: MutableList<Address> = LinkedList()
|
||||||
|
for (escapedAddress in escapedAddresses) {
|
||||||
|
addresses.add(fromSerialized(unescape(escapedAddress, delimiter)))
|
||||||
|
}
|
||||||
|
return addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toSerializedList(addresses: List<Address>, delimiter: Char): String {
|
||||||
|
Collections.sort(addresses)
|
||||||
|
val escapedAddresses: MutableList<String> = LinkedList()
|
||||||
|
for (address in addresses) {
|
||||||
|
escapedAddresses.add(escape(address.serialize(), delimiter))
|
||||||
|
}
|
||||||
|
return Util.join(escapedAddresses, delimiter.toString() + "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package org.session.libsession.messaging.threads
|
||||||
|
|
||||||
|
import android.text.TextUtils
|
||||||
|
import org.session.libsession.utilities.GroupUtil
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class GroupRecord(
|
||||||
|
val encodedId: String, val title: String, members: String?, val avatar: ByteArray,
|
||||||
|
val avatarId: Long, val avatarKey: ByteArray, val avatarContentType: String,
|
||||||
|
val relay: String, val isActive: Boolean, val avatarDigest: ByteArray, val isMms: Boolean, val url: String, admins: String?,
|
||||||
|
) {
|
||||||
|
var members: List<Address> = LinkedList<Address>()
|
||||||
|
var admins: List<Address> = LinkedList<Address>()
|
||||||
|
fun getId(): ByteArray {
|
||||||
|
return try {
|
||||||
|
GroupUtil.getDecodedGroupIDAsData(encodedId.toByteArray())
|
||||||
|
} catch (ioe: IOException) {
|
||||||
|
throw AssertionError(ioe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val isOpenGroup: Boolean
|
||||||
|
get() = Address.fromSerialized(encodedId).isOpenGroup
|
||||||
|
val isClosedGroup: Boolean
|
||||||
|
get() = Address.fromSerialized(encodedId).isClosedGroup
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (!TextUtils.isEmpty(members)) {
|
||||||
|
this.members = Address.fromSerializedList(members!!, ',')
|
||||||
|
}
|
||||||
|
if (!TextUtils.isEmpty(admins)) {
|
||||||
|
this.admins = Address.fromSerializedList(admins!!, ',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,47 +0,0 @@
|
|||||||
package org.session.libsession.utilities
|
|
||||||
|
|
||||||
object LKGroupUtilities {
|
|
||||||
const val CLOSED_GROUP_PREFIX = "__textsecure_group__!"
|
|
||||||
const val MMS_GROUP_PREFIX = "__signal_mms_group__!"
|
|
||||||
const val OPEN_GROUP_PREFIX = "__loki_public_chat_group__!"
|
|
||||||
|
|
||||||
fun getEncodedOpenGroupID(groupID: String): String {
|
|
||||||
return OPEN_GROUP_PREFIX + groupID
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getEncodedOpenGroupIDAsData(groupID: String): ByteArray {
|
|
||||||
return (OPEN_GROUP_PREFIX + groupID).toByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getEncodedClosedGroupID(groupID: String): String {
|
|
||||||
return CLOSED_GROUP_PREFIX + groupID
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getEncodedClosedGroupIDAsData(groupID: String): ByteArray {
|
|
||||||
return (CLOSED_GROUP_PREFIX + groupID).toByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getEncodedMMSGroupID(groupID: String): String {
|
|
||||||
return MMS_GROUP_PREFIX + groupID
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getEncodedMMSGroupIDAsData(groupID: String): ByteArray {
|
|
||||||
return (MMS_GROUP_PREFIX + groupID).toByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getEncodedGroupID(groupID: ByteArray): String {
|
|
||||||
return groupID.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDecodedGroupID(groupID: ByteArray): String {
|
|
||||||
val encodedGroupID = groupID.toString()
|
|
||||||
if (encodedGroupID.split("!").count() > 1) {
|
|
||||||
return encodedGroupID.split("!")[1]
|
|
||||||
}
|
|
||||||
return encodedGroupID.split("!")[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getDecodedGroupIDAsData(groupID: ByteArray): ByteArray {
|
|
||||||
return getDecodedGroupID(groupID).toByteArray()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user