diff --git a/libsession/src/main/java/org/session/libsession/messaging/Configuration.kt b/libsession/src/main/java/org/session/libsession/messaging/Configuration.kt deleted file mode 100644 index c544a972c7..0000000000 --- a/libsession/src/main/java/org/session/libsession/messaging/Configuration.kt +++ /dev/null @@ -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) - } - } -} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/threads/Address.kt b/libsession/src/main/java/org/session/libsession/messaging/threads/Address.kt new file mode 100644 index 0000000000..a4e01330a3 --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/messaging/threads/Address.kt @@ -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 { + 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 + 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, 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 + + init { + this.areaCode = Optional.fromNullable(areaCode) + } + } + + companion object { + private val TAG = ExternalAddressFormatter::class.java.simpleName + private val SHORT_COUNTRIES: HashSet = object : HashSet() { + 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 = object : Parcelable.Creator { + override fun createFromParcel(`in`: Parcel): Address { + return Address(`in`) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + val UNKNOWN = Address("Unknown") + private val TAG = Address::class.java.simpleName + private val cachedFormatter = AtomicReference>() + 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
{ + val escapedAddresses = split(serialized, delimiter) + val addresses: MutableList
= LinkedList() + for (escapedAddress in escapedAddresses) { + addresses.add(fromSerialized(unescape(escapedAddress, delimiter))) + } + return addresses + } + + fun toSerializedList(addresses: List
, delimiter: Char): String { + Collections.sort(addresses) + val escapedAddresses: MutableList = LinkedList() + for (address in addresses) { + escapedAddresses.add(escape(address.serialize(), delimiter)) + } + return Util.join(escapedAddresses, delimiter.toString() + "") + } + } + +} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/threads/GroupRecord.kt b/libsession/src/main/java/org/session/libsession/messaging/threads/GroupRecord.kt new file mode 100644 index 0000000000..ce19c18db8 --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/messaging/threads/GroupRecord.kt @@ -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
= LinkedList
() + var admins: List
= LinkedList
() + 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!!, ',') + } + } +} \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/utilities/LKGroupUtilities.kt b/libsession/src/main/java/org/session/libsession/utilities/LKGroupUtilities.kt deleted file mode 100644 index 5c47e0b53f..0000000000 --- a/libsession/src/main/java/org/session/libsession/utilities/LKGroupUtilities.kt +++ /dev/null @@ -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() - } -} \ No newline at end of file