mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-22 10:18:26 +00:00
Minor message type refactoring
This commit is contained in:
parent
11a89c0a76
commit
fa5edcefd5
@ -7,9 +7,6 @@ import org.session.libsession.messaging.threads.Address
|
|||||||
import org.session.libsession.utilities.GroupUtil
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsignal.service.loki.utilities.toHexString
|
import org.session.libsignal.service.loki.utilities.toHexString
|
||||||
|
|
||||||
typealias OpenGroupModel = OpenGroup
|
|
||||||
typealias OpenGroupV2Model = OpenGroupV2
|
|
||||||
|
|
||||||
sealed class Destination {
|
sealed class Destination {
|
||||||
|
|
||||||
class Contact(var publicKey: String) : Destination() {
|
class Contact(var publicKey: String) : Destination() {
|
||||||
@ -21,11 +18,12 @@ sealed class Destination {
|
|||||||
class OpenGroup(var channel: Long, var server: String) : Destination() {
|
class OpenGroup(var channel: Long, var server: String) : Destination() {
|
||||||
internal constructor(): this(0, "")
|
internal constructor(): this(0, "")
|
||||||
}
|
}
|
||||||
class OpenGroupV2(var room: String, var server: String): Destination() {
|
class OpenGroupV2(var room: String, var server: String) : Destination() {
|
||||||
internal constructor(): this("", "")
|
internal constructor(): this("", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun from(address: Address): Destination {
|
fun from(address: Address): Destination {
|
||||||
return when {
|
return when {
|
||||||
address.isContact -> {
|
address.isContact -> {
|
||||||
@ -39,10 +37,12 @@ sealed class Destination {
|
|||||||
address.isOpenGroup -> {
|
address.isOpenGroup -> {
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val threadID = storage.getThreadID(address.contactIdentifier())!!
|
val threadID = storage.getThreadID(address.contactIdentifier())!!
|
||||||
when (val openGroup = storage.getOpenGroup(threadID) ?: storage.getV2OpenGroup(threadID)) {
|
when (val openGroup = storage.getV2OpenGroup(threadID) ?: storage.getOpenGroup(threadID)) {
|
||||||
is OpenGroupModel -> OpenGroup(openGroup.channel, openGroup.server)
|
is org.session.libsession.messaging.open_groups.OpenGroup
|
||||||
is OpenGroupV2Model -> OpenGroupV2(openGroup.room, openGroup.server)
|
-> Destination.OpenGroup(openGroup.channel, openGroup.server)
|
||||||
else -> throw Exception("Invalid OpenGroup $openGroup")
|
is org.session.libsession.messaging.open_groups.OpenGroupV2
|
||||||
|
-> Destination.OpenGroupV2(openGroup.room, openGroup.server)
|
||||||
|
else -> throw Exception("Missing open group for thread with ID: $threadID.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -18,12 +18,10 @@ abstract class Message {
|
|||||||
open val isSelfSendValid: Boolean = false
|
open val isSelfSendValid: Boolean = false
|
||||||
|
|
||||||
open fun isValid(): Boolean {
|
open fun isValid(): Boolean {
|
||||||
sentTimestamp?.let {
|
val sentTimestamp = sentTimestamp
|
||||||
if (it <= 0) return false
|
if (sentTimestamp != null && sentTimestamp <= 0) { return false }
|
||||||
}
|
val receivedTimestamp = receivedTimestamp
|
||||||
receivedTimestamp?.let {
|
if (receivedTimestamp != null && receivedTimestamp <= 0) { return false }
|
||||||
if (it <= 0) return false
|
|
||||||
}
|
|
||||||
return sender != null && recipient != null
|
return sender != null && recipient != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +16,10 @@ import org.session.libsignal.utilities.Hex
|
|||||||
import org.session.libsignal.utilities.logging.Log
|
import org.session.libsignal.utilities.logging.Log
|
||||||
|
|
||||||
class ClosedGroupControlMessage() : ControlMessage() {
|
class ClosedGroupControlMessage() : ControlMessage() {
|
||||||
|
var kind: Kind? = null
|
||||||
|
|
||||||
override val ttl: Long = run {
|
override val ttl: Long get() {
|
||||||
when (kind) {
|
return when (kind) {
|
||||||
is Kind.EncryptionKeyPair -> 14 * 24 * 60 * 60 * 1000
|
is Kind.EncryptionKeyPair -> 14 * 24 * 60 * 60 * 1000
|
||||||
else -> 14 * 24 * 60 * 60 * 1000
|
else -> 14 * 24 * 60 * 60 * 1000
|
||||||
}
|
}
|
||||||
@ -26,31 +27,46 @@ class ClosedGroupControlMessage() : ControlMessage() {
|
|||||||
|
|
||||||
override val isSelfSendValid: Boolean = true
|
override val isSelfSendValid: Boolean = true
|
||||||
|
|
||||||
var kind: Kind? = null
|
override fun isValid(): Boolean {
|
||||||
|
val kind = kind
|
||||||
|
if (!super.isValid() || kind == null) return false
|
||||||
|
return when (kind) {
|
||||||
|
is Kind.New -> {
|
||||||
|
!kind.publicKey.isEmpty && kind.name.isNotEmpty() && kind.encryptionKeyPair?.publicKey != null
|
||||||
|
&& kind.encryptionKeyPair?.privateKey != null && kind.members.isNotEmpty() && kind.admins.isNotEmpty()
|
||||||
|
}
|
||||||
|
is Kind.EncryptionKeyPair -> true
|
||||||
|
is Kind.NameChange -> kind.name.isNotEmpty()
|
||||||
|
is Kind.MembersAdded -> kind.members.isNotEmpty()
|
||||||
|
is Kind.MembersRemoved -> kind.members.isNotEmpty()
|
||||||
|
is Kind.MemberLeft -> true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sealed class Kind {
|
sealed class Kind {
|
||||||
class New(var publicKey: ByteString, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<ByteString>, var admins: List<ByteString>) : Kind() {
|
class New(var publicKey: ByteString, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<ByteString>, var admins: List<ByteString>) : Kind() {
|
||||||
internal constructor(): this(ByteString.EMPTY, "", null, listOf(), listOf())
|
internal constructor() : this(ByteString.EMPTY, "", null, listOf(), listOf())
|
||||||
}
|
}
|
||||||
/// An encryption key pair encrypted for each member individually.
|
/** An encryption key pair encrypted for each member individually.
|
||||||
///
|
*
|
||||||
/// - Note: `publicKey` is only set when an encryption key pair is sent in a one-to-one context (i.e. not in a group).
|
* **Note:** `publicKey` is only set when an encryption key pair is sent in a one-to-one context (i.e. not in a group).
|
||||||
|
*/
|
||||||
class EncryptionKeyPair(var publicKey: ByteString?, var wrappers: Collection<KeyPairWrapper>) : Kind() {
|
class EncryptionKeyPair(var publicKey: ByteString?, var wrappers: Collection<KeyPairWrapper>) : Kind() {
|
||||||
internal constructor(): this(null, listOf())
|
internal constructor() : this(null, listOf())
|
||||||
}
|
}
|
||||||
class NameChange(var name: String) : Kind() {
|
class NameChange(var name: String) : Kind() {
|
||||||
internal constructor(): this("")
|
internal constructor() : this("")
|
||||||
}
|
}
|
||||||
class MembersAdded(var members: List<ByteString>) : Kind() {
|
class MembersAdded(var members: List<ByteString>) : Kind() {
|
||||||
internal constructor(): this(listOf())
|
internal constructor() : this(listOf())
|
||||||
}
|
}
|
||||||
class MembersRemoved(var members: List<ByteString>) : Kind() {
|
class MembersRemoved(var members: List<ByteString>) : Kind() {
|
||||||
internal constructor(): this(listOf())
|
internal constructor() : this(listOf())
|
||||||
}
|
}
|
||||||
class MemberLeft() : Kind()
|
class MemberLeft() : Kind()
|
||||||
|
|
||||||
val description: String =
|
val description: String =
|
||||||
when(this) {
|
when (this) {
|
||||||
is New -> "new"
|
is New -> "new"
|
||||||
is EncryptionKeyPair -> "encryptionKeyPair"
|
is EncryptionKeyPair -> "encryptionKeyPair"
|
||||||
is NameChange -> "nameChange"
|
is NameChange -> "nameChange"
|
||||||
@ -65,18 +81,19 @@ class ClosedGroupControlMessage() : ControlMessage() {
|
|||||||
|
|
||||||
fun fromProto(proto: SignalServiceProtos.Content): ClosedGroupControlMessage? {
|
fun fromProto(proto: SignalServiceProtos.Content): ClosedGroupControlMessage? {
|
||||||
if (!proto.hasDataMessage() || !proto.dataMessage.hasClosedGroupControlMessage()) return null
|
if (!proto.hasDataMessage() || !proto.dataMessage.hasClosedGroupControlMessage()) return null
|
||||||
val closedGroupControlMessageProto = proto.dataMessage?.closedGroupControlMessage!!
|
val closedGroupControlMessageProto = proto.dataMessage!!.closedGroupControlMessage!!
|
||||||
val kind: Kind
|
val kind: Kind
|
||||||
when (closedGroupControlMessageProto.type) {
|
when (closedGroupControlMessageProto.type!!) {
|
||||||
DataMessage.ClosedGroupControlMessage.Type.NEW -> {
|
DataMessage.ClosedGroupControlMessage.Type.NEW -> {
|
||||||
val publicKey = closedGroupControlMessageProto.publicKey ?: return null
|
val publicKey = closedGroupControlMessageProto.publicKey ?: return null
|
||||||
val name = closedGroupControlMessageProto.name ?: return null
|
val name = closedGroupControlMessageProto.name ?: return null
|
||||||
val encryptionKeyPairAsProto = closedGroupControlMessageProto.encryptionKeyPair ?: return null
|
val encryptionKeyPairAsProto = closedGroupControlMessageProto.encryptionKeyPair ?: return null
|
||||||
try {
|
try {
|
||||||
val encryptionKeyPair = ECKeyPair(DjbECPublicKey(encryptionKeyPairAsProto.publicKey.toByteArray()), DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
|
val encryptionKeyPair = ECKeyPair(DjbECPublicKey(encryptionKeyPairAsProto.publicKey.toByteArray()),
|
||||||
|
DjbECPrivateKey(encryptionKeyPairAsProto.privateKey.toByteArray()))
|
||||||
kind = Kind.New(publicKey, name, encryptionKeyPair, closedGroupControlMessageProto.membersList, closedGroupControlMessageProto.adminsList)
|
kind = Kind.New(publicKey, name, encryptionKeyPair, closedGroupControlMessageProto.membersList, closedGroupControlMessageProto.adminsList)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "Couldn't parse key pair")
|
Log.w(TAG, "Couldn't parse key pair from proto: $encryptionKeyPairAsProto.")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,26 +124,10 @@ class ClosedGroupControlMessage() : ControlMessage() {
|
|||||||
this.kind = kind
|
this.kind = kind
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isValid(): Boolean {
|
|
||||||
if (!super.isValid()) return false
|
|
||||||
val kind = kind ?: return false
|
|
||||||
return when(kind) {
|
|
||||||
is Kind.New -> {
|
|
||||||
!kind.publicKey.isEmpty && kind.name.isNotEmpty() && kind.encryptionKeyPair!!.publicKey != null
|
|
||||||
&& kind.encryptionKeyPair!!.privateKey != null && kind.members.isNotEmpty() && kind.admins.isNotEmpty()
|
|
||||||
}
|
|
||||||
is Kind.EncryptionKeyPair -> true
|
|
||||||
is Kind.NameChange -> kind.name.isNotEmpty()
|
|
||||||
is Kind.MembersAdded -> kind.members.isNotEmpty()
|
|
||||||
is Kind.MembersRemoved -> kind.members.isNotEmpty()
|
|
||||||
is Kind.MemberLeft -> true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toProto(): SignalServiceProtos.Content? {
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
val kind = kind
|
val kind = kind
|
||||||
if (kind == null) {
|
if (kind == null) {
|
||||||
Log.w(TAG, "Couldn't construct closed group update proto from: $this")
|
Log.w(TAG, "Couldn't construct closed group control message proto from: $this.")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -176,7 +177,7 @@ class ClosedGroupControlMessage() : ControlMessage() {
|
|||||||
contentProto.dataMessage = dataMessageProto.build()
|
contentProto.dataMessage = dataMessageProto.build()
|
||||||
return contentProto.build()
|
return contentProto.build()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "Couldn't construct closed group update proto from: $this")
|
Log.w(TAG, "Couldn't construct closed group control message proto from: $this.")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,6 +189,7 @@ class ClosedGroupControlMessage() : ControlMessage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun fromProto(proto: DataMessage.ClosedGroupControlMessage.KeyPairWrapper): KeyPairWrapper {
|
fun fromProto(proto: DataMessage.ClosedGroupControlMessage.KeyPairWrapper): KeyPairWrapper {
|
||||||
return KeyPairWrapper(proto.publicKey.toByteArray().toHexString(), proto.encryptedKeyPair)
|
return KeyPairWrapper(proto.publicKey.toByteArray().toHexString(), proto.encryptedKeyPair)
|
||||||
}
|
}
|
||||||
@ -199,7 +201,6 @@ class ClosedGroupControlMessage() : ControlMessage() {
|
|||||||
val result = DataMessage.ClosedGroupControlMessage.KeyPairWrapper.newBuilder()
|
val result = DataMessage.ClosedGroupControlMessage.KeyPairWrapper.newBuilder()
|
||||||
result.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(publicKey))
|
result.publicKey = ByteString.copyFrom(Hex.fromStringCondensed(publicKey))
|
||||||
result.encryptedKeyPair = encryptedKeyPair
|
result.encryptedKeyPair = encryptedKeyPair
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
result.build()
|
result.build()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -14,12 +14,15 @@ import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded
|
|||||||
import org.session.libsignal.service.loki.utilities.toHexString
|
import org.session.libsignal.service.loki.utilities.toHexString
|
||||||
import org.session.libsignal.utilities.Hex
|
import org.session.libsignal.utilities.Hex
|
||||||
|
|
||||||
class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups: List<String>, var contacts: List<Contact>, var displayName: String, var profilePicture: String?, var profileKey: ByteArray): ControlMessage() {
|
class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups: List<String>, var contacts: List<Contact>,
|
||||||
|
var displayName: String, var profilePicture: String?, var profileKey: ByteArray) : ControlMessage() {
|
||||||
|
|
||||||
|
override val isSelfSendValid: Boolean = true
|
||||||
|
|
||||||
class ClosedGroup(var publicKey: String, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<String>, var admins: List<String>) {
|
class ClosedGroup(var publicKey: String, var name: String, var encryptionKeyPair: ECKeyPair?, var members: List<String>, var admins: List<String>) {
|
||||||
val isValid: Boolean get() = members.isNotEmpty() && admins.isNotEmpty()
|
val isValid: Boolean get() = members.isNotEmpty() && admins.isNotEmpty()
|
||||||
|
|
||||||
internal constructor(): this("", "", null, listOf(), listOf())
|
internal constructor() : this("", "", null, listOf(), listOf())
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return name
|
return name
|
||||||
@ -56,7 +59,7 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
|
|
||||||
class Contact(var publicKey: String, var name: String, var profilePicture: String?, var profileKey: ByteArray?) {
|
class Contact(var publicKey: String, var name: String, var profilePicture: String?, var profileKey: ByteArray?) {
|
||||||
|
|
||||||
internal constructor(): this("", "", null, null)
|
internal constructor() : this("", "", null, null)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -66,8 +69,7 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
val name = proto.name
|
val name = proto.name
|
||||||
val profilePicture = if (proto.hasProfilePicture()) proto.profilePicture else null
|
val profilePicture = if (proto.hasProfilePicture()) proto.profilePicture else null
|
||||||
val profileKey = if (proto.hasProfileKey()) proto.profileKey.toByteArray() else null
|
val profileKey = if (proto.hasProfileKey()) proto.profileKey.toByteArray() else null
|
||||||
|
return Contact(publicKey, name, profilePicture, profileKey)
|
||||||
return Contact(publicKey,name,profilePicture,profileKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,18 +81,18 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
if (!this.profilePicture.isNullOrEmpty()) {
|
val profilePicture = profilePicture
|
||||||
result.profilePicture = this.profilePicture
|
if (!profilePicture.isNullOrEmpty()) {
|
||||||
|
result.profilePicture = profilePicture
|
||||||
}
|
}
|
||||||
if (this.profileKey != null) {
|
val profileKey = profileKey
|
||||||
result.profileKey = ByteString.copyFrom(this.profileKey)
|
if (profileKey != null) {
|
||||||
|
result.profileKey = ByteString.copyFrom(profileKey)
|
||||||
}
|
}
|
||||||
return result.build()
|
return result.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isSelfSendValid: Boolean = true
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun getCurrent(contacts: List<Contact>): ConfigurationMessage? {
|
fun getCurrent(contacts: List<Contact>): ConfigurationMessage? {
|
||||||
@ -103,24 +105,22 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
val profilePicture = TextSecurePreferences.getProfilePictureURL(context)
|
val profilePicture = TextSecurePreferences.getProfilePictureURL(context)
|
||||||
val profileKey = ProfileKeyUtil.getProfileKey(context)
|
val profileKey = ProfileKeyUtil.getProfileKey(context)
|
||||||
val groups = storage.getAllGroups()
|
val groups = storage.getAllGroups()
|
||||||
for (groupRecord in groups) {
|
for (group in groups) {
|
||||||
if (groupRecord.isClosedGroup) {
|
if (group.isClosedGroup) {
|
||||||
if (!groupRecord.members.contains(Address.fromSerialized(storage.getUserPublicKey()!!))) continue
|
if (!group.members.contains(Address.fromSerialized(storage.getUserPublicKey()!!))) continue
|
||||||
val groupPublicKey = GroupUtil.doubleDecodeGroupID(groupRecord.encodedId).toHexString()
|
val groupPublicKey = GroupUtil.doubleDecodeGroupID(group.encodedId).toHexString()
|
||||||
val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: continue
|
val encryptionKeyPair = storage.getLatestClosedGroupEncryptionKeyPair(groupPublicKey) ?: continue
|
||||||
val closedGroup = ClosedGroup(groupPublicKey, groupRecord.title, encryptionKeyPair, groupRecord.members.map { it.serialize() }, groupRecord.admins.map { it.serialize() })
|
val closedGroup = ClosedGroup(groupPublicKey, group.title, encryptionKeyPair, group.members.map { it.serialize() }, group.admins.map { it.serialize() })
|
||||||
closedGroups.add(closedGroup)
|
closedGroups.add(closedGroup)
|
||||||
}
|
}
|
||||||
if (groupRecord.isOpenGroup) {
|
if (group.isOpenGroup) {
|
||||||
val threadID = storage.getThreadID(groupRecord.encodedId) ?: continue
|
val threadID = storage.getThreadID(group.encodedId) ?: continue
|
||||||
val openGroup = storage.getOpenGroup(threadID)
|
val openGroup = storage.getOpenGroup(threadID)
|
||||||
val openGroupV2 = storage.getV2OpenGroup(threadID)
|
val openGroupV2 = storage.getV2OpenGroup(threadID)
|
||||||
|
|
||||||
val shareUrl = openGroup?.server ?: openGroupV2?.toJoinUrl() ?: continue
|
val shareUrl = openGroup?.server ?: openGroupV2?.toJoinUrl() ?: continue
|
||||||
openGroups.add(shareUrl)
|
openGroups.add(shareUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConfigurationMessage(closedGroups, openGroups, contacts, displayName, profilePicture, profileKey)
|
return ConfigurationMessage(closedGroups, openGroups, contacts, displayName, profilePicture, profileKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +145,7 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
configurationProto.addAllOpenGroups(openGroups)
|
configurationProto.addAllOpenGroups(openGroups)
|
||||||
configurationProto.addAllContacts(this.contacts.mapNotNull { it.toProto() })
|
configurationProto.addAllContacts(this.contacts.mapNotNull { it.toProto() })
|
||||||
configurationProto.displayName = displayName
|
configurationProto.displayName = displayName
|
||||||
|
val profilePicture = profilePicture
|
||||||
if (!profilePicture.isNullOrEmpty()) {
|
if (!profilePicture.isNullOrEmpty()) {
|
||||||
configurationProto.profilePicture = profilePicture
|
configurationProto.profilePicture = profilePicture
|
||||||
}
|
}
|
||||||
@ -157,10 +158,10 @@ class ConfigurationMessage(var closedGroups: List<ClosedGroup>, var openGroups:
|
|||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return """
|
return """
|
||||||
ConfigurationMessage(
|
ConfigurationMessage(
|
||||||
closedGroups: ${(closedGroups)}
|
closedGroups: ${(closedGroups)},
|
||||||
openGroups: ${(openGroups)}
|
openGroups: ${(openGroups)},
|
||||||
displayName: $displayName
|
displayName: $displayName,
|
||||||
profilePicture: $profilePicture
|
profilePicture: $profilePicture,
|
||||||
profileKey: $profileKey
|
profileKey: $profileKey
|
||||||
)
|
)
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
@ -2,5 +2,4 @@ package org.session.libsession.messaging.messages.control
|
|||||||
|
|
||||||
import org.session.libsession.messaging.messages.Message
|
import org.session.libsession.messaging.messages.Message
|
||||||
|
|
||||||
abstract class ControlMessage : Message() {
|
abstract class ControlMessage : Message()
|
||||||
}
|
|
@ -3,7 +3,7 @@ package org.session.libsession.messaging.messages.control
|
|||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
import org.session.libsignal.utilities.logging.Log
|
import org.session.libsignal.utilities.logging.Log
|
||||||
|
|
||||||
class DataExtractionNotification(): ControlMessage() {
|
class DataExtractionNotification() : ControlMessage() {
|
||||||
var kind: Kind? = null
|
var kind: Kind? = null
|
||||||
|
|
||||||
sealed class Kind {
|
sealed class Kind {
|
||||||
@ -39,8 +39,8 @@ class DataExtractionNotification(): ControlMessage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isValid(): Boolean {
|
override fun isValid(): Boolean {
|
||||||
if (!super.isValid()) return false
|
val kind = kind
|
||||||
val kind = kind ?: return false
|
if (!super.isValid() || kind == null) return false
|
||||||
return when(kind) {
|
return when(kind) {
|
||||||
is Kind.Screenshot -> true
|
is Kind.Screenshot -> true
|
||||||
is Kind.MediaSaved -> kind.timestamp > 0
|
is Kind.MediaSaved -> kind.timestamp > 0
|
||||||
|
@ -6,13 +6,20 @@ import org.session.libsignal.utilities.logging.Log
|
|||||||
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
class ExpirationTimerUpdate() : ControlMessage() {
|
class ExpirationTimerUpdate() : ControlMessage() {
|
||||||
/// In the case of a sync message, the public key of the person the message was targeted at.
|
/** In the case of a sync message, the public key of the person the message was targeted at.
|
||||||
/// - Note: `nil` if this isn't a sync message.
|
*
|
||||||
|
* **Note:** `nil` if this isn't a sync message.
|
||||||
|
*/
|
||||||
var syncTarget: String? = null
|
var syncTarget: String? = null
|
||||||
var duration: Int? = 0
|
var duration: Int? = 0
|
||||||
|
|
||||||
override val isSelfSendValid: Boolean = true
|
override val isSelfSendValid: Boolean = true
|
||||||
|
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
return duration != null
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "ExpirationTimerUpdate"
|
const val TAG = "ExpirationTimerUpdate"
|
||||||
|
|
||||||
@ -26,21 +33,11 @@ class ExpirationTimerUpdate() : ControlMessage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(syncTarget: String?, duration: Int) : this() {
|
internal constructor(syncTarget: String? = null, duration: Int) : this() {
|
||||||
this.syncTarget = syncTarget
|
this.syncTarget = syncTarget
|
||||||
this.duration = duration
|
this.duration = duration
|
||||||
}
|
}
|
||||||
|
|
||||||
internal constructor(duration: Int) : this() {
|
|
||||||
this.syncTarget = null
|
|
||||||
this.duration = duration
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isValid(): Boolean {
|
|
||||||
if (!super.isValid()) return false
|
|
||||||
return duration != null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toProto(): SignalServiceProtos.Content? {
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
val duration = duration
|
val duration = duration
|
||||||
if (duration == null) {
|
if (duration == null) {
|
||||||
|
@ -6,6 +6,13 @@ import org.session.libsignal.utilities.logging.Log
|
|||||||
class ReadReceipt() : ControlMessage() {
|
class ReadReceipt() : ControlMessage() {
|
||||||
var timestamps: List<Long>? = null
|
var timestamps: List<Long>? = null
|
||||||
|
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
val timestamps = timestamps ?: return false
|
||||||
|
if (timestamps.isNotEmpty()) { return true }
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "ReadReceipt"
|
const val TAG = "ReadReceipt"
|
||||||
|
|
||||||
@ -22,13 +29,6 @@ class ReadReceipt() : ControlMessage() {
|
|||||||
this.timestamps = timestamps
|
this.timestamps = timestamps
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isValid(): Boolean {
|
|
||||||
if (!super.isValid()) return false
|
|
||||||
val timestamps = timestamps ?: return false
|
|
||||||
if (timestamps.isNotEmpty()) { return true }
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toProto(): SignalServiceProtos.Content? {
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
val timestamps = timestamps
|
val timestamps = timestamps
|
||||||
if (timestamps == null) {
|
if (timestamps == null) {
|
||||||
|
@ -4,9 +4,15 @@ import org.session.libsignal.service.internal.push.SignalServiceProtos
|
|||||||
import org.session.libsignal.utilities.logging.Log
|
import org.session.libsignal.utilities.logging.Log
|
||||||
|
|
||||||
class TypingIndicator() : ControlMessage() {
|
class TypingIndicator() : ControlMessage() {
|
||||||
override val ttl: Long = 30 * 1000
|
|
||||||
var kind: Kind? = null
|
var kind: Kind? = null
|
||||||
|
|
||||||
|
override val ttl: Long = 20 * 1000
|
||||||
|
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
return kind != null
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "TypingIndicator"
|
const val TAG = "TypingIndicator"
|
||||||
|
|
||||||
@ -41,11 +47,6 @@ class TypingIndicator() : ControlMessage() {
|
|||||||
this.kind = kind
|
this.kind = kind
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isValid(): Boolean {
|
|
||||||
if (!super.isValid()) return false
|
|
||||||
return kind != null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toProto(): SignalServiceProtos.Content? {
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
val timestamp = sentTimestamp
|
val timestamp = sentTimestamp
|
||||||
val kind = kind
|
val kind = kind
|
||||||
|
@ -10,6 +10,10 @@ class LinkPreview() {
|
|||||||
var url: String? = null
|
var url: String? = null
|
||||||
var attachmentID: Long? = 0
|
var attachmentID: Long? = 0
|
||||||
|
|
||||||
|
fun isValid(): Boolean {
|
||||||
|
return (title != null && url != null && attachmentID != null)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "LinkPreview"
|
const val TAG = "LinkPreview"
|
||||||
|
|
||||||
@ -20,11 +24,8 @@ class LinkPreview() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun from(signalLinkPreview: SignalLinkPreiview?): LinkPreview? {
|
fun from(signalLinkPreview: SignalLinkPreiview?): LinkPreview? {
|
||||||
return if (signalLinkPreview == null) {
|
if (signalLinkPreview == null) { return null }
|
||||||
null
|
return LinkPreview(signalLinkPreview.title, signalLinkPreview.url, signalLinkPreview.attachmentId?.rowId)
|
||||||
} else {
|
|
||||||
LinkPreview(signalLinkPreview.title, signalLinkPreview.url, signalLinkPreview.attachmentId?.rowId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,10 +35,6 @@ class LinkPreview() {
|
|||||||
this.attachmentID = attachmentID
|
this.attachmentID = attachmentID
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isValid(): Boolean {
|
|
||||||
return (title != null && url != null && attachmentID != null)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toProto(): SignalServiceProtos.DataMessage.Preview? {
|
fun toProto(): SignalServiceProtos.DataMessage.Preview? {
|
||||||
val url = url
|
val url = url
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
@ -46,10 +43,10 @@ class LinkPreview() {
|
|||||||
}
|
}
|
||||||
val linkPreviewProto = SignalServiceProtos.DataMessage.Preview.newBuilder()
|
val linkPreviewProto = SignalServiceProtos.DataMessage.Preview.newBuilder()
|
||||||
linkPreviewProto.url = url
|
linkPreviewProto.url = url
|
||||||
title?.let { linkPreviewProto.title = title }
|
title?.let { linkPreviewProto.title = it }
|
||||||
val attachmentID = attachmentID
|
val database = MessagingModuleConfiguration.shared.messageDataProvider
|
||||||
attachmentID?.let {
|
attachmentID?.let {
|
||||||
MessagingModuleConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(attachmentID)?.let {
|
database.getSignalAttachmentPointer(it)?.let {
|
||||||
val attachmentProto = Attachment.createAttachmentPointer(it)
|
val attachmentProto = Attachment.createAttachmentPointer(it)
|
||||||
linkPreviewProto.image = attachmentProto
|
linkPreviewProto.image = attachmentProto
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,13 @@ class Profile() {
|
|||||||
val displayName = profileProto.displayName ?: return null
|
val displayName = profileProto.displayName ?: return null
|
||||||
val profileKey = proto.profileKey
|
val profileKey = proto.profileKey
|
||||||
val profilePictureURL = profileProto.profilePicture
|
val profilePictureURL = profileProto.profilePicture
|
||||||
profileKey?.let {
|
if (profileKey != null && profilePictureURL != null) {
|
||||||
profilePictureURL?.let {
|
return Profile(displayName, profileKey.toByteArray(), profilePictureURL)
|
||||||
return Profile(displayName = displayName, profileKey = profileKey.toByteArray(), profilePictureURL = profilePictureURL)
|
} else {
|
||||||
}
|
|
||||||
}
|
|
||||||
return Profile(displayName)
|
return Profile(displayName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal constructor(displayName: String, profileKey: ByteArray? = null, profilePictureURL: String? = null) : this() {
|
internal constructor(displayName: String, profileKey: ByteArray? = null, profilePictureURL: String? = null) : this() {
|
||||||
this.displayName = displayName
|
this.displayName = displayName
|
||||||
@ -35,16 +34,14 @@ class Profile() {
|
|||||||
fun toProto(): SignalServiceProtos.DataMessage? {
|
fun toProto(): SignalServiceProtos.DataMessage? {
|
||||||
val displayName = displayName
|
val displayName = displayName
|
||||||
if (displayName == null) {
|
if (displayName == null) {
|
||||||
Log.w(TAG, "Couldn't construct link preview proto from: $this")
|
Log.w(TAG, "Couldn't construct profile proto from: $this")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder()
|
val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder()
|
||||||
val profileProto = SignalServiceProtos.DataMessage.LokiProfile.newBuilder()
|
val profileProto = SignalServiceProtos.DataMessage.LokiProfile.newBuilder()
|
||||||
profileProto.displayName = displayName
|
profileProto.displayName = displayName
|
||||||
val profileKey = profileKey
|
profileKey?.let { dataMessageProto.profileKey = ByteString.copyFrom(it) }
|
||||||
profileKey?.let { dataMessageProto.profileKey = ByteString.copyFrom(profileKey) }
|
profilePictureURL?.let { profileProto.profilePicture = it }
|
||||||
val profilePictureURL = profilePictureURL
|
|
||||||
profilePictureURL?.let { profileProto.profilePicture = profilePictureURL }
|
|
||||||
// Build
|
// Build
|
||||||
try {
|
try {
|
||||||
dataMessageProto.profile = profileProto.build()
|
dataMessageProto.profile = profileProto.build()
|
||||||
|
@ -13,6 +13,10 @@ class Quote() {
|
|||||||
var text: String? = null
|
var text: String? = null
|
||||||
var attachmentID: Long? = null
|
var attachmentID: Long? = null
|
||||||
|
|
||||||
|
fun isValid(): Boolean {
|
||||||
|
return (timestamp != null && publicKey != null)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "Quote"
|
const val TAG = "Quote"
|
||||||
|
|
||||||
@ -24,12 +28,9 @@ class Quote() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun from(signalQuote: SignalQuote?): Quote? {
|
fun from(signalQuote: SignalQuote?): Quote? {
|
||||||
return if (signalQuote == null) {
|
if (signalQuote == null) { return null }
|
||||||
null
|
|
||||||
} else {
|
|
||||||
val attachmentID = (signalQuote.attachments?.firstOrNull() as? DatabaseAttachment)?.attachmentId?.rowId
|
val attachmentID = (signalQuote.attachments?.firstOrNull() as? DatabaseAttachment)?.attachmentId?.rowId
|
||||||
Quote(signalQuote.id, signalQuote.author.serialize(), signalQuote.text, attachmentID)
|
return Quote(signalQuote.id, signalQuote.author.serialize(), signalQuote.text, attachmentID)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +41,6 @@ class Quote() {
|
|||||||
this.attachmentID = attachmentID
|
this.attachmentID = attachmentID
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isValid(): Boolean {
|
|
||||||
return (timestamp != null && publicKey != null)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toProto(): SignalServiceProtos.DataMessage.Quote? {
|
fun toProto(): SignalServiceProtos.DataMessage.Quote? {
|
||||||
val timestamp = timestamp
|
val timestamp = timestamp
|
||||||
val publicKey = publicKey
|
val publicKey = publicKey
|
||||||
@ -54,7 +51,7 @@ class Quote() {
|
|||||||
val quoteProto = SignalServiceProtos.DataMessage.Quote.newBuilder()
|
val quoteProto = SignalServiceProtos.DataMessage.Quote.newBuilder()
|
||||||
quoteProto.id = timestamp
|
quoteProto.id = timestamp
|
||||||
quoteProto.author = publicKey
|
quoteProto.author = publicKey
|
||||||
text?.let { quoteProto.text = text }
|
text?.let { quoteProto.text = it }
|
||||||
addAttachmentsIfNeeded(quoteProto)
|
addAttachmentsIfNeeded(quoteProto)
|
||||||
// Build
|
// Build
|
||||||
try {
|
try {
|
||||||
@ -66,23 +63,23 @@ class Quote() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addAttachmentsIfNeeded(quoteProto: SignalServiceProtos.DataMessage.Quote.Builder) {
|
private fun addAttachmentsIfNeeded(quoteProto: SignalServiceProtos.DataMessage.Quote.Builder) {
|
||||||
if (attachmentID == null) return
|
val attachmentID = attachmentID ?: return
|
||||||
val attachment = MessagingModuleConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(attachmentID!!)
|
val database = MessagingModuleConfiguration.shared.messageDataProvider
|
||||||
if (attachment == null) {
|
val pointer = database.getSignalAttachmentPointer(attachmentID)
|
||||||
|
if (pointer == null) {
|
||||||
Log.w(TAG, "Ignoring invalid attachment for quoted message.")
|
Log.w(TAG, "Ignoring invalid attachment for quoted message.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (attachment.url.isNullOrEmpty()) {
|
if (pointer.url.isNullOrEmpty()) {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
//TODO equivalent to iOS's preconditionFailure
|
Log.w(TAG,"Sending a message before all associated attachments have been uploaded.")
|
||||||
Log.d(TAG,"Sending a message before all associated attachments have been uploaded.")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val quotedAttachmentProto = SignalServiceProtos.DataMessage.Quote.QuotedAttachment.newBuilder()
|
val quotedAttachmentProto = SignalServiceProtos.DataMessage.Quote.QuotedAttachment.newBuilder()
|
||||||
quotedAttachmentProto.contentType = attachment.contentType
|
quotedAttachmentProto.contentType = pointer.contentType
|
||||||
if (attachment.fileName.isPresent) quotedAttachmentProto.fileName = attachment.fileName.get()
|
if (pointer.fileName.isPresent) { quotedAttachmentProto.fileName = pointer.fileName.get() }
|
||||||
quotedAttachmentProto.thumbnail = Attachment.createAttachmentPointer(attachment)
|
quotedAttachmentProto.thumbnail = Attachment.createAttachmentPointer(pointer)
|
||||||
try {
|
try {
|
||||||
quoteProto.addAttachments(quotedAttachmentProto.build())
|
quoteProto.addAttachments(quotedAttachmentProto.build())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -12,6 +12,10 @@ import org.session.libsignal.utilities.logging.Log
|
|||||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment
|
import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment
|
||||||
|
|
||||||
class VisibleMessage : Message() {
|
class VisibleMessage : Message() {
|
||||||
|
/** In the case of a sync message, the public key of the person the message was targeted at.
|
||||||
|
*
|
||||||
|
* **Note:** `nil` if this isn't a sync message.
|
||||||
|
*/
|
||||||
var syncTarget: String? = null
|
var syncTarget: String? = null
|
||||||
var text: String? = null
|
var text: String? = null
|
||||||
val attachmentIDs: MutableList<Long> = mutableListOf()
|
val attachmentIDs: MutableList<Long> = mutableListOf()
|
||||||
@ -21,46 +25,7 @@ class VisibleMessage : Message() {
|
|||||||
|
|
||||||
override val isSelfSendValid: Boolean = true
|
override val isSelfSendValid: Boolean = true
|
||||||
|
|
||||||
companion object {
|
// region Validation
|
||||||
const val TAG = "VisibleMessage"
|
|
||||||
|
|
||||||
fun fromProto(proto: SignalServiceProtos.Content): VisibleMessage? {
|
|
||||||
val dataMessage = if (proto.hasDataMessage()) proto.dataMessage else return null
|
|
||||||
val result = VisibleMessage()
|
|
||||||
if (dataMessage.hasSyncTarget()) {
|
|
||||||
result.syncTarget = dataMessage.syncTarget
|
|
||||||
}
|
|
||||||
result.text = dataMessage.body
|
|
||||||
// Attachments are handled in MessageReceiver
|
|
||||||
val quoteProto = if (dataMessage.hasQuote()) dataMessage.quote else null
|
|
||||||
quoteProto?.let {
|
|
||||||
val quote = Quote.fromProto(quoteProto)
|
|
||||||
quote?.let { result.quote = quote }
|
|
||||||
}
|
|
||||||
val linkPreviewProto = dataMessage.previewList.firstOrNull()
|
|
||||||
linkPreviewProto?.let {
|
|
||||||
val linkPreview = LinkPreview.fromProto(linkPreviewProto)
|
|
||||||
linkPreview?.let { result.linkPreview = linkPreview }
|
|
||||||
}
|
|
||||||
// TODO Contact
|
|
||||||
val profile = Profile.fromProto(dataMessage)
|
|
||||||
profile?.let { result.profile = profile }
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addSignalAttachments(signalAttachments: List<SignalAttachment>) {
|
|
||||||
val attachmentIDs = signalAttachments.map {
|
|
||||||
val databaseAttachment = it as DatabaseAttachment
|
|
||||||
databaseAttachment.attachmentId.rowId
|
|
||||||
}
|
|
||||||
this.attachmentIDs.addAll(attachmentIDs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isMediaMessage(): Boolean {
|
|
||||||
return attachmentIDs.isNotEmpty() || quote != null || linkPreview != null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isValid(): Boolean {
|
override fun isValid(): Boolean {
|
||||||
if (!super.isValid()) return false
|
if (!super.isValid()) return false
|
||||||
if (attachmentIDs.isNotEmpty()) return true
|
if (attachmentIDs.isNotEmpty()) return true
|
||||||
@ -68,56 +33,84 @@ class VisibleMessage : Message() {
|
|||||||
if (text.isNotEmpty()) return true
|
if (text.isNotEmpty()) return true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Proto Conversion
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VisibleMessage"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): VisibleMessage? {
|
||||||
|
val dataMessage = proto.dataMessage ?: return null
|
||||||
|
val result = VisibleMessage()
|
||||||
|
if (dataMessage.hasSyncTarget()) { result.syncTarget = dataMessage.syncTarget }
|
||||||
|
result.text = dataMessage.body
|
||||||
|
// Attachments are handled in MessageReceiver
|
||||||
|
val quoteProto = if (dataMessage.hasQuote()) dataMessage.quote else null
|
||||||
|
if (quoteProto != null) {
|
||||||
|
val quote = Quote.fromProto(quoteProto)
|
||||||
|
result.quote = quote
|
||||||
|
}
|
||||||
|
val linkPreviewProto = dataMessage.previewList.firstOrNull()
|
||||||
|
if (linkPreviewProto != null) {
|
||||||
|
val linkPreview = LinkPreview.fromProto(linkPreviewProto)
|
||||||
|
result.linkPreview = linkPreview
|
||||||
|
}
|
||||||
|
// TODO: Contact
|
||||||
|
val profile = Profile.fromProto(dataMessage)
|
||||||
|
if (profile != null) { result.profile = profile }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun toProto(): SignalServiceProtos.Content? {
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
val proto = SignalServiceProtos.Content.newBuilder()
|
val proto = SignalServiceProtos.Content.newBuilder()
|
||||||
val dataMessage: SignalServiceProtos.DataMessage.Builder
|
val dataMessage: SignalServiceProtos.DataMessage.Builder
|
||||||
// Profile
|
// Profile
|
||||||
val profile = profile
|
val profileProto = profile?.let { it.toProto() }
|
||||||
val profileProto = profile?.toProto()
|
|
||||||
if (profileProto != null) {
|
if (profileProto != null) {
|
||||||
dataMessage = profileProto.toBuilder()
|
dataMessage = profileProto.toBuilder()
|
||||||
} else {
|
} else {
|
||||||
dataMessage = SignalServiceProtos.DataMessage.newBuilder()
|
dataMessage = SignalServiceProtos.DataMessage.newBuilder()
|
||||||
}
|
}
|
||||||
// Text
|
// Text
|
||||||
text?.let { dataMessage.body = text }
|
if (text != null) { dataMessage.body = text }
|
||||||
// Quote
|
// Quote
|
||||||
quote?.let {
|
val quoteProto = quote?.let { it.toProto() }
|
||||||
val quoteProto = it.toProto()
|
if (quoteProto != null) {
|
||||||
if (quoteProto != null) dataMessage.quote = quoteProto
|
dataMessage.quote = quoteProto
|
||||||
}
|
}
|
||||||
//Link preview
|
// Link preview
|
||||||
linkPreview?.let {
|
val linkPreviewProto = linkPreview?.let { it.toProto() }
|
||||||
val linkPreviewProto = it.toProto()
|
if (linkPreviewProto != null) {
|
||||||
linkPreviewProto?.let {
|
|
||||||
dataMessage.addAllPreview(listOf(linkPreviewProto))
|
dataMessage.addAllPreview(listOf(linkPreviewProto))
|
||||||
}
|
}
|
||||||
}
|
// Attachments
|
||||||
//Attachments
|
val database = MessagingModuleConfiguration.shared.messageDataProvider
|
||||||
val attachments = attachmentIDs.mapNotNull { MessagingModuleConfiguration.shared.messageDataProvider.getSignalAttachmentPointer(it) }
|
val attachments = attachmentIDs.mapNotNull { database.getSignalAttachmentPointer(it) }
|
||||||
if (!attachments.all { !it.url.isNullOrEmpty() }) {
|
if (attachments.any { it.url.isNullOrEmpty() }) {
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
//TODO equivalent to iOS's preconditionFailure
|
Log.w(TAG, "Sending a message before all associated attachments have been uploaded.")
|
||||||
Log.d(TAG, "Sending a message before all associated attachments have been uploaded.")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val attachmentPointers = attachments.mapNotNull { Attachment.createAttachmentPointer(it) }
|
val pointers = attachments.mapNotNull { Attachment.createAttachmentPointer(it) }
|
||||||
dataMessage.addAllAttachments(attachmentPointers)
|
dataMessage.addAllAttachments(pointers)
|
||||||
// TODO Contact
|
// TODO: Contact
|
||||||
// Expiration timer
|
// Expiration timer
|
||||||
// TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation
|
// TODO: We * want * expiration timer updates to be explicit. But currently Android will disable the expiration timer for a conversation
|
||||||
// if it receives a message without the current expiration timer value attached to it...
|
// if it receives a message without the current expiration timer value attached to it...
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
val storage = MessagingModuleConfiguration.shared.storage
|
||||||
val context = MessagingModuleConfiguration.shared.context
|
val context = MessagingModuleConfiguration.shared.context
|
||||||
val expiration = if (storage.isClosedGroup(recipient!!)) Recipient.from(context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(recipient!!)), false).expireMessages
|
val expiration = if (storage.isClosedGroup(recipient!!)) {
|
||||||
else Recipient.from(context, Address.fromSerialized(recipient!!), false).expireMessages
|
Recipient.from(context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(recipient!!)), false).expireMessages
|
||||||
|
} else {
|
||||||
|
Recipient.from(context, Address.fromSerialized(recipient!!), false).expireMessages
|
||||||
|
}
|
||||||
dataMessage.expireTimer = expiration
|
dataMessage.expireTimer = expiration
|
||||||
// Group context
|
// Group context
|
||||||
if (storage.isClosedGroup(recipient!!)) {
|
if (storage.isClosedGroup(recipient!!)) {
|
||||||
try {
|
try {
|
||||||
setGroupContext(dataMessage)
|
setGroupContext(dataMessage)
|
||||||
} catch(e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "Couldn't construct visible message proto from: $this")
|
Log.w(TAG, "Couldn't construct visible message proto from: $this")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -135,4 +128,17 @@ class VisibleMessage : Message() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
fun addSignalAttachments(signalAttachments: List<SignalAttachment>) {
|
||||||
|
val attachmentIDs = signalAttachments.map {
|
||||||
|
val databaseAttachment = it as DatabaseAttachment
|
||||||
|
databaseAttachment.attachmentId.rowId
|
||||||
|
}
|
||||||
|
this.attachmentIDs.addAll(attachmentIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isMediaMessage(): Boolean {
|
||||||
|
return attachmentIDs.isNotEmpty() || quote != null || linkPreview != null
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user