mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-18 05:57:44 +00:00
commit
67d53fc3f5
@ -38,7 +38,10 @@ dependencies {
|
|||||||
implementation 'androidx.core:core-ktx:1.3.2'
|
implementation 'androidx.core:core-ktx:1.3.2'
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
implementation 'com.google.android.material:material:1.2.1'
|
implementation 'com.google.android.material:material:1.2.1'
|
||||||
|
implementation "com.google.protobuf:protobuf-java:$protobufVersion"
|
||||||
testImplementation 'junit:junit:4.+'
|
testImplementation 'junit:junit:4.+'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||||
|
|
||||||
|
implementation project(":libsignal")
|
||||||
}
|
}
|
@ -1,5 +1,12 @@
|
|||||||
package org.session.messaging.messages
|
package org.session.libsession.messaging.messages
|
||||||
|
|
||||||
enum class Destination {
|
sealed class Destination {
|
||||||
|
|
||||||
|
class Contact(val publicKey: String)
|
||||||
|
class ClosedGroup(val groupPublicKey: String)
|
||||||
|
class OpenGroup(val channel: Long, val server: String)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
//TODO need to implement the equivalent to TSThread and then implement from(...)
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,30 @@
|
|||||||
package org.session.messaging.messages
|
package org.session.libsession.messaging.messages
|
||||||
|
|
||||||
open class Message {
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
abstract class Message {
|
||||||
|
|
||||||
|
var id: String? = null
|
||||||
|
var threadID: String? = null
|
||||||
|
var sentTimestamp: Long? = null
|
||||||
|
var receivedTimestamp: Long? = null
|
||||||
|
var recipient: String? = null
|
||||||
|
var sender: String? = null
|
||||||
|
var groupPublicKey: String? = null
|
||||||
|
var openGroupServerMessageID: Long? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
val ttl = 2 * 24 * 60 * 60 * 1000 //TODO not sure about that declaration
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
open fun isValid(): Boolean {
|
||||||
|
sentTimestamp = if (sentTimestamp!! > 0) sentTimestamp else return false
|
||||||
|
receivedTimestamp = if (receivedTimestamp!! > 0) receivedTimestamp else return false
|
||||||
|
return sender != null && recipient != null
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun toProto(): SignalServiceProtos.Content?
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,154 @@
|
|||||||
package org.session.messaging.messages.control
|
package org.session.libsession.messaging.messages.control
|
||||||
|
|
||||||
class ClosedGroupUpdate : ControlMessage() {
|
import com.google.protobuf.ByteString
|
||||||
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
import org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey
|
||||||
|
|
||||||
|
class ClosedGroupUpdate() : ControlMessage() {
|
||||||
|
|
||||||
|
var kind: Kind? = null
|
||||||
|
|
||||||
|
// Kind enum
|
||||||
|
sealed class Kind {
|
||||||
|
class New(val groupPublicKey: ByteArray, val name: String, val groupPrivateKey: ByteArray, val senderKeys: Collection<org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey>, val members: Collection<ByteArray>, val admins: Collection<ByteArray>) : Kind()
|
||||||
|
class Info(val groupPublicKey: ByteArray, val name: String, val senderKeys: Collection<org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey>, val members: Collection<ByteArray>, val admins: Collection<ByteArray>) : Kind()
|
||||||
|
class SenderKeyRequest(val groupPublicKey: ByteArray) : Kind()
|
||||||
|
class SenderKey(val groupPublicKey: ByteArray, val senderKey: org.session.libsignal.service.loki.protocol.closedgroups.ClosedGroupSenderKey) : Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "ClosedGroupUpdate"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): ClosedGroupUpdate? {
|
||||||
|
val closedGroupUpdateProto = proto.dataMessage?.closedGroupUpdate ?: return null
|
||||||
|
val groupPublicKey = closedGroupUpdateProto.groupPublicKey
|
||||||
|
var kind: Kind
|
||||||
|
when(closedGroupUpdateProto.type) {
|
||||||
|
SignalServiceProtos.ClosedGroupUpdate.Type.NEW -> {
|
||||||
|
val name = closedGroupUpdateProto.name ?: return null
|
||||||
|
val groupPrivateKey = closedGroupUpdateProto.groupPrivateKey ?: return null
|
||||||
|
val senderKeys = closedGroupUpdateProto.senderKeysList.map { ClosedGroupSenderKey.fromProto(it) }
|
||||||
|
kind = Kind.New(
|
||||||
|
groupPublicKey = groupPublicKey.toByteArray(),
|
||||||
|
name = name,
|
||||||
|
groupPrivateKey = groupPrivateKey.toByteArray(),
|
||||||
|
senderKeys = senderKeys,
|
||||||
|
members = closedGroupUpdateProto.membersList.map { it.toByteArray() },
|
||||||
|
admins = closedGroupUpdateProto.adminsList.map { it.toByteArray() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SignalServiceProtos.ClosedGroupUpdate.Type.INFO -> {
|
||||||
|
val name = closedGroupUpdateProto.name ?: return null
|
||||||
|
val senderKeys = closedGroupUpdateProto.senderKeysList.map { ClosedGroupSenderKey.fromProto(it) }
|
||||||
|
kind = Kind.Info(
|
||||||
|
groupPublicKey = groupPublicKey.toByteArray(),
|
||||||
|
name = name,
|
||||||
|
senderKeys = senderKeys,
|
||||||
|
members = closedGroupUpdateProto.membersList.map { it.toByteArray() },
|
||||||
|
admins = closedGroupUpdateProto.adminsList.map { it.toByteArray() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SignalServiceProtos.ClosedGroupUpdate.Type.SENDER_KEY_REQUEST -> {
|
||||||
|
kind = Kind.SenderKeyRequest(groupPublicKey = groupPublicKey.toByteArray())
|
||||||
|
}
|
||||||
|
SignalServiceProtos.ClosedGroupUpdate.Type.SENDER_KEY -> {
|
||||||
|
val senderKeyProto = closedGroupUpdateProto.senderKeysList?.first() ?: return null
|
||||||
|
kind = Kind.SenderKey(
|
||||||
|
groupPublicKey = groupPublicKey.toByteArray(),
|
||||||
|
senderKey = ClosedGroupSenderKey.fromProto(senderKeyProto)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ClosedGroupUpdate(kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
internal constructor(kind: Kind?) : this() {
|
||||||
|
this.kind = kind
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
val kind = kind ?: return false
|
||||||
|
when(kind) {
|
||||||
|
is Kind.New -> {
|
||||||
|
return !kind.groupPublicKey.isEmpty() && !kind.name.isEmpty() && !kind.groupPrivateKey.isEmpty() && !kind.members.isEmpty() && !kind.admins.isEmpty()
|
||||||
|
}
|
||||||
|
is Kind.Info -> {
|
||||||
|
return !kind.groupPublicKey.isEmpty() && !kind.name.isEmpty() && !kind.members.isEmpty() && !kind.admins.isEmpty()
|
||||||
|
}
|
||||||
|
is Kind.SenderKeyRequest -> {
|
||||||
|
return !kind.groupPublicKey.isEmpty()
|
||||||
|
}
|
||||||
|
is Kind.SenderKey -> {
|
||||||
|
return !kind.groupPublicKey.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
|
val kind = kind
|
||||||
|
if (kind == null) {
|
||||||
|
Log.w(TAG, "Couldn't construct closed group update proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val closedGroupUpdate: SignalServiceProtos.ClosedGroupUpdate.Builder = SignalServiceProtos.ClosedGroupUpdate.newBuilder()
|
||||||
|
when (kind) {
|
||||||
|
is Kind.New -> {
|
||||||
|
closedGroupUpdate.groupPublicKey = ByteString.copyFrom(kind.groupPublicKey)
|
||||||
|
closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdate.Type.NEW
|
||||||
|
closedGroupUpdate.name = kind.name
|
||||||
|
closedGroupUpdate.groupPrivateKey = ByteString.copyFrom(kind.groupPrivateKey)
|
||||||
|
closedGroupUpdate.addAllSenderKeys(kind.senderKeys.map { it.toProto() })
|
||||||
|
closedGroupUpdate.addAllMembers(kind.members.map { ByteString.copyFrom(it) })
|
||||||
|
closedGroupUpdate.addAllAdmins(kind.admins.map { ByteString.copyFrom(it) })
|
||||||
|
}
|
||||||
|
is Kind.Info -> {
|
||||||
|
closedGroupUpdate.groupPublicKey = ByteString.copyFrom(kind.groupPublicKey)
|
||||||
|
closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdate.Type.INFO
|
||||||
|
closedGroupUpdate.name = kind.name
|
||||||
|
closedGroupUpdate.addAllSenderKeys(kind.senderKeys.map { it.toProto() })
|
||||||
|
closedGroupUpdate.addAllMembers(kind.members.map { ByteString.copyFrom(it) })
|
||||||
|
closedGroupUpdate.addAllAdmins(kind.admins.map { ByteString.copyFrom(it) })
|
||||||
|
}
|
||||||
|
is Kind.SenderKeyRequest -> {
|
||||||
|
closedGroupUpdate.groupPublicKey = ByteString.copyFrom(kind.groupPublicKey)
|
||||||
|
closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdate.Type.SENDER_KEY_REQUEST
|
||||||
|
}
|
||||||
|
is Kind.SenderKey -> {
|
||||||
|
closedGroupUpdate.groupPublicKey = ByteString.copyFrom(kind.groupPublicKey)
|
||||||
|
closedGroupUpdate.type = SignalServiceProtos.ClosedGroupUpdate.Type.SENDER_KEY
|
||||||
|
closedGroupUpdate.addAllSenderKeys(listOf( kind.senderKey.toProto() ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val contentProto = SignalServiceProtos.Content.newBuilder()
|
||||||
|
val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder()
|
||||||
|
dataMessageProto.closedGroupUpdate = closedGroupUpdate.build()
|
||||||
|
contentProto.dataMessage = dataMessageProto.build()
|
||||||
|
return contentProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct closed group update proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// extension functions to class ClosedGroupSenderKey
|
||||||
|
|
||||||
|
private fun ClosedGroupSenderKey.Companion.fromProto(proto: SignalServiceProtos.ClosedGroupUpdate.SenderKey): ClosedGroupSenderKey {
|
||||||
|
return ClosedGroupSenderKey(chainKey = proto.chainKey.toByteArray(), keyIndex = proto.keyIndex, publicKey = proto.publicKey.toByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ClosedGroupSenderKey.toProto(): SignalServiceProtos.ClosedGroupUpdate.SenderKey {
|
||||||
|
val proto = SignalServiceProtos.ClosedGroupUpdate.SenderKey.newBuilder()
|
||||||
|
proto.chainKey = ByteString.copyFrom(chainKey)
|
||||||
|
proto.keyIndex = keyIndex
|
||||||
|
proto.publicKey = ByteString.copyFrom(publicKey)
|
||||||
|
return proto.build()
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package org.session.messaging.messages.control
|
package org.session.libsession.messaging.messages.control
|
||||||
|
|
||||||
import org.session.messaging.messages.Message
|
import org.session.libsession.messaging.messages.Message
|
||||||
|
|
||||||
open class ControlMessage : Message() {
|
abstract class ControlMessage : Message() {
|
||||||
}
|
}
|
@ -1,4 +1,51 @@
|
|||||||
package org.session.messaging.messages.control
|
package org.session.libsession.messaging.messages.control
|
||||||
|
|
||||||
class ExpirationTimerUpdate : ControlMessage() {
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
class ExpirationTimerUpdate() : ControlMessage() {
|
||||||
|
|
||||||
|
var duration: Int? = 0
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "ExpirationTimerUpdate"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): ExpirationTimerUpdate? {
|
||||||
|
val dataMessageProto = proto.dataMessage ?: return null
|
||||||
|
val isExpirationTimerUpdate = (dataMessageProto.flags and SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE) != 0 //TODO validate that 'and' operator equivalent to Swift '&'
|
||||||
|
if (!isExpirationTimerUpdate) return null
|
||||||
|
val duration = dataMessageProto.expireTimer
|
||||||
|
return ExpirationTimerUpdate(duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//constructor
|
||||||
|
internal constructor(duration: Int) : this() {
|
||||||
|
this.duration = duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
return duration != null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
|
val duration = duration
|
||||||
|
if (duration == null) {
|
||||||
|
Log.w(TAG, "Couldn't construct expiration timer update proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder()
|
||||||
|
dataMessageProto.flags = SignalServiceProtos.DataMessage.Flags.EXPIRATION_TIMER_UPDATE_VALUE
|
||||||
|
dataMessageProto.expireTimer = duration
|
||||||
|
val contentProto = SignalServiceProtos.Content.newBuilder()
|
||||||
|
try {
|
||||||
|
contentProto.dataMessage = dataMessageProto.build()
|
||||||
|
return contentProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct expiration timer update proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,53 @@
|
|||||||
package org.session.messaging.messages.control
|
package org.session.libsession.messaging.messages.control
|
||||||
|
|
||||||
class ReadReceipt : ControlMessage() {
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
class ReadReceipt() : ControlMessage() {
|
||||||
|
|
||||||
|
var timestamps: LongArray? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "ReadReceipt"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): ReadReceipt? {
|
||||||
|
val receiptProto = proto.receiptMessage ?: return null
|
||||||
|
if (receiptProto.type != SignalServiceProtos.ReceiptMessage.Type.READ) return null
|
||||||
|
val timestamps = receiptProto.timestampList
|
||||||
|
if (timestamps.isEmpty()) return null
|
||||||
|
return ReadReceipt(timestamps = timestamps.toLongArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//constructor
|
||||||
|
internal constructor(timestamps: LongArray?) : this() {
|
||||||
|
this.timestamps = timestamps
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
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? {
|
||||||
|
val timestamps = timestamps
|
||||||
|
if (timestamps == null) {
|
||||||
|
Log.w(ExpirationTimerUpdate.TAG, "Couldn't construct read receipt proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val receiptProto = SignalServiceProtos.ReceiptMessage.newBuilder()
|
||||||
|
receiptProto.type = SignalServiceProtos.ReceiptMessage.Type.READ
|
||||||
|
receiptProto.addAllTimestamp(timestamps.asIterable())
|
||||||
|
val contentProto = SignalServiceProtos.Content.newBuilder()
|
||||||
|
try {
|
||||||
|
contentProto.receiptMessage = receiptProto.build()
|
||||||
|
return contentProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(ExpirationTimerUpdate.TAG, "Couldn't construct read receipt proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,75 @@
|
|||||||
package org.session.messaging.messages.control
|
package org.session.libsession.messaging.messages.control
|
||||||
|
|
||||||
class TypingIndicator : ControlMessage() {
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
class TypingIndicator() : ControlMessage() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "TypingIndicator"
|
||||||
|
|
||||||
|
//val ttl: 30 * 1000 //TODO
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): TypingIndicator? {
|
||||||
|
val typingIndicatorProto = proto.typingMessage ?: return null
|
||||||
|
val kind = Kind.fromProto(typingIndicatorProto.action)
|
||||||
|
return TypingIndicator(kind = kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kind enum
|
||||||
|
enum class Kind {
|
||||||
|
STARTED,
|
||||||
|
STOPPED,
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun fromProto(proto: SignalServiceProtos.TypingMessage.Action): Kind =
|
||||||
|
when (proto) {
|
||||||
|
SignalServiceProtos.TypingMessage.Action.STARTED -> STARTED
|
||||||
|
SignalServiceProtos.TypingMessage.Action.STOPPED -> STOPPED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toProto(): SignalServiceProtos.TypingMessage.Action {
|
||||||
|
when (this) {
|
||||||
|
STARTED -> return SignalServiceProtos.TypingMessage.Action.STARTED
|
||||||
|
STOPPED -> return SignalServiceProtos.TypingMessage.Action.STOPPED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var kind: Kind? = null
|
||||||
|
|
||||||
|
//constructor
|
||||||
|
internal constructor(kind: Kind) : this() {
|
||||||
|
this.kind = kind
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
return kind != null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
|
val timestamp = sentTimestamp
|
||||||
|
val kind = kind
|
||||||
|
if (timestamp == null || kind == null) {
|
||||||
|
Log.w(TAG, "Couldn't construct typing indicator proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val typingIndicatorProto = SignalServiceProtos.TypingMessage.newBuilder()
|
||||||
|
typingIndicatorProto.timestamp = timestamp
|
||||||
|
typingIndicatorProto.action = kind.toProto()
|
||||||
|
val contentProto = SignalServiceProtos.Content.newBuilder()
|
||||||
|
try {
|
||||||
|
contentProto.typingMessage = typingIndicatorProto.build()
|
||||||
|
return contentProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct typing indicator proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,37 @@
|
|||||||
package org.session.messaging.messages.control.unused
|
package org.session.libsession.messaging.messages.control.unused
|
||||||
|
|
||||||
import org.session.messaging.messages.control.ControlMessage
|
import com.google.protobuf.ByteString
|
||||||
|
import org.session.libsession.messaging.messages.control.ControlMessage
|
||||||
|
import org.session.libsession.messaging.messages.control.TypingIndicator
|
||||||
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
import java.security.SecureRandom
|
||||||
|
|
||||||
class NullMessage : ControlMessage() {
|
class NullMessage() : ControlMessage() {
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "NullMessage"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): NullMessage? {
|
||||||
|
if (proto.nullMessage == null) return null
|
||||||
|
return NullMessage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
|
val nullMessageProto = SignalServiceProtos.NullMessage.newBuilder()
|
||||||
|
val sr = SecureRandom()
|
||||||
|
val paddingSize = sr.nextInt(512)
|
||||||
|
val padding = ByteArray(paddingSize)
|
||||||
|
nullMessageProto.padding = ByteString.copyFrom(padding)
|
||||||
|
val contentProto = SignalServiceProtos.Content.newBuilder()
|
||||||
|
try {
|
||||||
|
contentProto.nullMessage = nullMessageProto.build()
|
||||||
|
return contentProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct null message proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,81 @@
|
|||||||
package org.session.messaging.messages.control.unused
|
package org.session.libsession.messaging.messages.control.unused
|
||||||
|
|
||||||
import org.session.messaging.messages.control.ControlMessage
|
import com.google.protobuf.ByteString
|
||||||
|
import org.session.libsession.messaging.messages.control.ControlMessage
|
||||||
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
|
import org.session.libsession.messaging.messages.control.TypingIndicator
|
||||||
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.libsignal.state.PreKeyBundle
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
import java.security.SecureRandom
|
||||||
|
|
||||||
class SessionRequest : ControlMessage() {
|
class SessionRequest() : ControlMessage() {
|
||||||
|
|
||||||
|
var preKeyBundle: PreKeyBundle? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "SessionRequest"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): SessionRequest? {
|
||||||
|
if (proto.nullMessage == null) return null
|
||||||
|
val preKeyBundleProto = proto.preKeyBundleMessage ?: return null
|
||||||
|
val registrationID: Int = 0
|
||||||
|
//TODO looks like database stuff here
|
||||||
|
/*iOS code: Configuration.shared.storage.with { transaction in
|
||||||
|
registrationID = Configuration.shared.storage.getOrGenerateRegistrationID(using: transaction)
|
||||||
|
}*/
|
||||||
|
val preKeyBundle = PreKeyBundle(
|
||||||
|
registrationID,
|
||||||
|
1,
|
||||||
|
preKeyBundleProto.preKeyId,
|
||||||
|
null, //TODO preKeyBundleProto.preKey,
|
||||||
|
0, //TODO preKeyBundleProto.signedKey,
|
||||||
|
null, //TODO preKeyBundleProto.signedKeyId,
|
||||||
|
preKeyBundleProto.signature.toByteArray(),
|
||||||
|
null, //TODO preKeyBundleProto.identityKey
|
||||||
|
)
|
||||||
|
return SessionRequest(preKeyBundle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//constructor
|
||||||
|
internal constructor(preKeyBundle: PreKeyBundle) : this() {
|
||||||
|
this.preKeyBundle = preKeyBundle
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
return preKeyBundle != null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(): SignalServiceProtos.Content? {
|
||||||
|
val preKeyBundle = preKeyBundle
|
||||||
|
if (preKeyBundle == null) {
|
||||||
|
Log.w(TAG, "Couldn't construct session request proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val nullMessageProto = SignalServiceProtos.NullMessage.newBuilder()
|
||||||
|
val sr = SecureRandom()
|
||||||
|
val paddingSize = sr.nextInt(512)
|
||||||
|
val padding = ByteArray(paddingSize)
|
||||||
|
nullMessageProto.padding = ByteString.copyFrom(padding)
|
||||||
|
val preKeyBundleProto = SignalServiceProtos.PreKeyBundleMessage.newBuilder()
|
||||||
|
//TODO preKeyBundleProto.identityKey = preKeyBundle.identityKey
|
||||||
|
preKeyBundleProto.deviceId = preKeyBundle.deviceId
|
||||||
|
preKeyBundleProto.preKeyId = preKeyBundle.preKeyId
|
||||||
|
//TODO preKeyBundleProto.preKey = preKeyBundle.preKeyPublic
|
||||||
|
preKeyBundleProto.signedKeyId = preKeyBundle.signedPreKeyId
|
||||||
|
//TODO preKeyBundleProto.signedKey = preKeyBundle.signedPreKeyPublic
|
||||||
|
preKeyBundleProto.signature = ByteString.copyFrom(preKeyBundle.signedPreKeySignature)
|
||||||
|
val contentProto = SignalServiceProtos.Content.newBuilder()
|
||||||
|
try {
|
||||||
|
contentProto.nullMessage = nullMessageProto.build()
|
||||||
|
contentProto.preKeyBundleMessage = preKeyBundleProto.build()
|
||||||
|
return contentProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct session request proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package org.session.libsession.messaging.messages.visible
|
||||||
|
|
||||||
|
import android.util.Size
|
||||||
|
import android.webkit.MimeTypeMap
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URL
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
|
class Attachment : VisibleMessage<SignalServiceProtos.AttachmentPointer?>() {
|
||||||
|
|
||||||
|
var fileName: String? = null
|
||||||
|
var contentType: String? = null
|
||||||
|
var key: ByteArray? = null
|
||||||
|
var digest: ByteArray? = null
|
||||||
|
var kind: Kind? = null
|
||||||
|
var caption: String? = null
|
||||||
|
var size: Size? = null
|
||||||
|
var sizeInBytes: Int? = 0
|
||||||
|
var url: String? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromProto(proto: SignalServiceProtos.AttachmentPointer): Attachment? {
|
||||||
|
val result = Attachment()
|
||||||
|
result.fileName = proto.fileName
|
||||||
|
fun inferContentType(): String {
|
||||||
|
val fileName = result.fileName ?: return "application/octet-stream" //TODO find equivalent to OWSMimeTypeApplicationOctetStream
|
||||||
|
val fileExtension = File(fileName).extension
|
||||||
|
val mimeTypeMap = MimeTypeMap.getSingleton()
|
||||||
|
return mimeTypeMap.getMimeTypeFromExtension(fileExtension) ?: "application/octet-stream" //TODO check that it's correct
|
||||||
|
}
|
||||||
|
result.contentType = proto.contentType ?: inferContentType()
|
||||||
|
result.key = proto.key.toByteArray()
|
||||||
|
result.digest = proto.digest.toByteArray()
|
||||||
|
val kind: Kind
|
||||||
|
if (proto.hasFlags() && (proto.flags and SignalServiceProtos.AttachmentPointer.Flags.VOICE_MESSAGE_VALUE) > 0) { //TODO validate that 'and' operator = swift '&'
|
||||||
|
kind = Kind.VOICEMESSAGE
|
||||||
|
} else {
|
||||||
|
kind = Kind.GENERIC
|
||||||
|
}
|
||||||
|
result.kind = kind
|
||||||
|
result.caption = if (proto.hasCaption()) proto.caption else null
|
||||||
|
val size: Size
|
||||||
|
if (proto.hasWidth() && proto.width > 0 && proto.hasHeight() && proto.height > 0) {
|
||||||
|
size = Size(proto.width, proto.height)
|
||||||
|
} else {
|
||||||
|
size = Size(0,0) //TODO check that it's equivalent to swift: CGSize.zero
|
||||||
|
}
|
||||||
|
result.size = size
|
||||||
|
result.sizeInBytes = if (proto.size > 0) proto.size else null
|
||||||
|
result. url = proto.url
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Kind {
|
||||||
|
VOICEMESSAGE,
|
||||||
|
GENERIC
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
// key and digest can be nil for open group attachments
|
||||||
|
return (contentType != null && kind != null && size != null && sizeInBytes != null && url != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(transaction: String): SignalServiceProtos.AttachmentPointer? {
|
||||||
|
TODO("Not implemented")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package org.session.libsession.messaging.messages.visible
|
||||||
|
|
||||||
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
class BaseVisibleMessage() : VisibleMessage<SignalServiceProtos.Content?>() {
|
||||||
|
|
||||||
|
var text: String? = null
|
||||||
|
var attachmentIDs = ArrayList<String>()
|
||||||
|
var quote: Quote? = null
|
||||||
|
var linkPreview: LinkPreview? = null
|
||||||
|
var contact: Contact? = null
|
||||||
|
var profile: Profile? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "BaseVisibleMessage"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): BaseVisibleMessage? {
|
||||||
|
val dataMessage = proto.dataMessage ?: return null
|
||||||
|
val result = BaseVisibleMessage()
|
||||||
|
result.text = dataMessage.body
|
||||||
|
// Attachments are handled in MessageReceiver
|
||||||
|
val quoteProto = dataMessage.quote
|
||||||
|
quoteProto?.let {
|
||||||
|
val quote = Quote.fromProto(quoteProto)
|
||||||
|
quote?.let { result.quote = quote }
|
||||||
|
}
|
||||||
|
val linkPreviewProto = dataMessage.previewList.first()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
if (attachmentIDs.isNotEmpty()) return true
|
||||||
|
val text = text?.trim() ?: return false
|
||||||
|
if (text.isNotEmpty()) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(transaction: String): SignalServiceProtos.Content? {
|
||||||
|
val proto = SignalServiceProtos.Content.newBuilder()
|
||||||
|
var attachmentIDs = this.attachmentIDs
|
||||||
|
val dataMessage: SignalServiceProtos.DataMessage.Builder
|
||||||
|
// Profile
|
||||||
|
val profile = profile
|
||||||
|
val profileProto = profile?.toSSProto()
|
||||||
|
if (profileProto != null) {
|
||||||
|
dataMessage = profileProto.toBuilder()
|
||||||
|
} else {
|
||||||
|
dataMessage = SignalServiceProtos.DataMessage.newBuilder()
|
||||||
|
}
|
||||||
|
// Text
|
||||||
|
text?.let { dataMessage.body = text }
|
||||||
|
// Quote
|
||||||
|
val quotedAttachmentID = quote?.attachmentID
|
||||||
|
quotedAttachmentID?.let {
|
||||||
|
val index = attachmentIDs.indexOf(quotedAttachmentID)
|
||||||
|
if (index >= 0) { attachmentIDs.removeAt(index) }
|
||||||
|
}
|
||||||
|
val quote = quote
|
||||||
|
quote?.let {
|
||||||
|
val quoteProto = quote.toProto(transaction)
|
||||||
|
if (quoteProto != null) dataMessage.quote = quoteProto
|
||||||
|
}
|
||||||
|
//Link preview
|
||||||
|
val linkPreviewAttachmentID = linkPreview?.attachmentID
|
||||||
|
linkPreviewAttachmentID?.let {
|
||||||
|
val index = attachmentIDs.indexOf(quotedAttachmentID)
|
||||||
|
if (index >= 0) { attachmentIDs.removeAt(index) }
|
||||||
|
}
|
||||||
|
val linkPreview = linkPreview
|
||||||
|
linkPreview?.let {
|
||||||
|
val linkPreviewProto = linkPreview.toProto(transaction)
|
||||||
|
linkPreviewProto?.let {
|
||||||
|
dataMessage.addAllPreview(listOf(linkPreviewProto))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Attachments
|
||||||
|
// TODO I'm blocking on that one...
|
||||||
|
//swift: let attachments = attachmentIDs.compactMap { TSAttachmentStream.fetch(uniqueId: $0, transaction: transaction) }
|
||||||
|
|
||||||
|
// TODO Contact
|
||||||
|
// Build
|
||||||
|
try {
|
||||||
|
proto.dataMessage = dataMessage.build()
|
||||||
|
return proto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct visible message proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,16 @@
|
|||||||
package org.session.messaging.messages.visible
|
package org.session.libsession.messaging.messages.visible
|
||||||
|
|
||||||
internal class Contact {
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
class Contact : VisibleMessage<SignalServiceProtos.DataMessage.Contact?>() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromProto(proto: SignalServiceProtos.Content): Contact? {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(transaction: String): SignalServiceProtos.DataMessage.Contact? {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,58 @@
|
|||||||
package org.session.messaging.messages.visible
|
package org.session.libsession.messaging.messages.visible
|
||||||
|
|
||||||
internal class LinkPreview {
|
import org.session.libsession.messaging.messages.control.TypingIndicator
|
||||||
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
class LinkPreview() : VisibleMessage<SignalServiceProtos.DataMessage.Preview?>(){
|
||||||
|
|
||||||
|
var title: String? = null
|
||||||
|
var url: String? = null
|
||||||
|
var attachmentID: String? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LinkPreview"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.DataMessage.Preview): LinkPreview? {
|
||||||
|
val title = proto.title
|
||||||
|
val url = proto.url
|
||||||
|
return LinkPreview(title, url, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//constructor
|
||||||
|
internal constructor(title: String?, url: String, attachmentID: String?) : this() {
|
||||||
|
this.title = title
|
||||||
|
this.url = url
|
||||||
|
this.attachmentID = attachmentID
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// validation
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
return (title != null && url != null && attachmentID != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(transaction: String): SignalServiceProtos.DataMessage.Preview? {
|
||||||
|
val url = url
|
||||||
|
if (url == null) {
|
||||||
|
Log.w(TAG, "Couldn't construct link preview proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val linkPreviewProto = SignalServiceProtos.DataMessage.Preview.newBuilder()
|
||||||
|
linkPreviewProto.url = url
|
||||||
|
title?.let { linkPreviewProto.title = title }
|
||||||
|
val attachmentID = attachmentID
|
||||||
|
attachmentID?.let {
|
||||||
|
//TODO database stuff
|
||||||
|
}
|
||||||
|
// Build
|
||||||
|
try {
|
||||||
|
return linkPreviewProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct link preview proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,64 @@
|
|||||||
package org.session.messaging.messages.visible
|
package org.session.libsession.messaging.messages.visible
|
||||||
|
|
||||||
internal class Profile {
|
import com.google.protobuf.ByteString
|
||||||
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
class Profile() : VisibleMessage<SignalServiceProtos.DataMessage?>() {
|
||||||
|
|
||||||
|
var displayName: String? = null
|
||||||
|
var profileKey: ByteArray? = null
|
||||||
|
var profilePictureURL: String? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "Profile"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.DataMessage): Profile? {
|
||||||
|
val profileProto = proto.profile ?: return null
|
||||||
|
val displayName = profileProto.displayName ?: return null
|
||||||
|
val profileKey = proto.profileKey
|
||||||
|
val profilePictureURL = profileProto.profilePictureURL
|
||||||
|
profileKey?.let {
|
||||||
|
val profilePictureURL = profilePictureURL
|
||||||
|
profilePictureURL?.let {
|
||||||
|
return Profile(displayName = displayName, profileKey = profileKey.toByteArray(), profilePictureURL = profilePictureURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Profile(displayName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//constructor
|
||||||
|
internal constructor(displayName: String, profileKey: ByteArray? = null, profilePictureURL: String? = null) : this() {
|
||||||
|
this.displayName = displayName
|
||||||
|
this.profileKey = profileKey
|
||||||
|
this.profilePictureURL = profilePictureURL
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toSSProto(): SignalServiceProtos.DataMessage? {
|
||||||
|
return this.toProto("")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(transaction: String): SignalServiceProtos.DataMessage? {
|
||||||
|
val displayName = displayName
|
||||||
|
if (displayName == null) {
|
||||||
|
Log.w(TAG, "Couldn't construct link preview proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val dataMessageProto = SignalServiceProtos.DataMessage.newBuilder()
|
||||||
|
val profileProto = SignalServiceProtos.LokiUserProfile.newBuilder()
|
||||||
|
profileProto.displayName = displayName
|
||||||
|
val profileKey = profileKey
|
||||||
|
profileKey?.let { dataMessageProto.profileKey = ByteString.copyFrom(profileKey) }
|
||||||
|
val profilePictureURL = profilePictureURL
|
||||||
|
profilePictureURL?.let { profileProto.profilePictureURL = profilePictureURL }
|
||||||
|
// Build
|
||||||
|
try {
|
||||||
|
dataMessageProto.profile = profileProto.build()
|
||||||
|
return dataMessageProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct profile proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,72 @@
|
|||||||
package org.session.messaging.messages.visible
|
package org.session.libsession.messaging.messages.visible
|
||||||
|
|
||||||
internal class Quote {
|
import org.session.libsignal.libsignal.logging.Log
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
|
class Quote() : VisibleMessage<SignalServiceProtos.DataMessage.Quote?>() {
|
||||||
|
|
||||||
|
var timestamp: Long? = 0
|
||||||
|
var publicKey: String? = null
|
||||||
|
var text: String? = null
|
||||||
|
var attachmentID: String? = null
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "Quote"
|
||||||
|
|
||||||
|
fun fromProto(proto: SignalServiceProtos.DataMessage.Quote): Quote? {
|
||||||
|
val timestamp = proto.id
|
||||||
|
val publicKey = proto.author
|
||||||
|
val text = proto.text
|
||||||
|
return Quote(timestamp, publicKey, text, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//constructor
|
||||||
|
internal constructor(timestamp: Long, publicKey: String, text: String?, attachmentID: String?) : this() {
|
||||||
|
this.timestamp = timestamp
|
||||||
|
this.publicKey = publicKey
|
||||||
|
this.text = text
|
||||||
|
this.attachmentID = attachmentID
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// validation
|
||||||
|
override fun isValid(): Boolean {
|
||||||
|
if (!super.isValid()) return false
|
||||||
|
return (timestamp != null && publicKey != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toProto(transaction: String): SignalServiceProtos.DataMessage.Quote? {
|
||||||
|
val timestamp = timestamp
|
||||||
|
val publicKey = publicKey
|
||||||
|
if (timestamp == null || publicKey == null) {
|
||||||
|
Log.w(TAG, "Couldn't construct quote proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val quoteProto = SignalServiceProtos.DataMessage.Quote.newBuilder()
|
||||||
|
quoteProto.id = timestamp
|
||||||
|
quoteProto.author = publicKey
|
||||||
|
text?.let { quoteProto.text = text }
|
||||||
|
addAttachmentsIfNeeded(quoteProto, transaction)
|
||||||
|
// Build
|
||||||
|
try {
|
||||||
|
return quoteProto.build()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct quote proto from: $this")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addAttachmentsIfNeeded(quoteProto: SignalServiceProtos.DataMessage.Quote.Builder, transaction: String) {
|
||||||
|
val attachmentID = attachmentID ?: return
|
||||||
|
//TODO databas stuff
|
||||||
|
val quotedAttachmentProto = SignalServiceProtos.DataMessage.Quote.QuotedAttachment.newBuilder()
|
||||||
|
//TODO more database related stuff
|
||||||
|
//quotedAttachmentProto.contentType =
|
||||||
|
try {
|
||||||
|
quoteProto.addAttachments(quotedAttachmentProto.build())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.w(TAG, "Couldn't construct quoted attachment proto from: $this")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,15 @@
|
|||||||
package org.session.messaging.messages.visible
|
package org.session.libsession.messaging.messages.visible
|
||||||
|
|
||||||
import org.session.messaging.messages.Message
|
import org.session.libsession.messaging.messages.Message
|
||||||
|
import org.session.libsignal.service.internal.push.SignalServiceProtos
|
||||||
|
|
||||||
class VisibleMessage : Message() {
|
abstract class VisibleMessage<out T: com.google.protobuf.MessageOrBuilder?> : Message() {
|
||||||
|
|
||||||
|
abstract fun toProto(transaction: String): T
|
||||||
|
|
||||||
|
final override fun toProto(): SignalServiceProtos.Content? {
|
||||||
|
//we don't need to implement this method in subclasses
|
||||||
|
//TODO it just needs an equivalent to swift: preconditionFailure("Use toProto(using:) if that exists...
|
||||||
|
TODO("Not implemented")
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +0,0 @@
|
|||||||
package org.session.messaging.messages.visible.attachments
|
|
||||||
|
|
||||||
internal class Attachment {
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user