You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-android/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt

141 lines
5.5 KiB
Kotlin

package org.session.libsession.messaging.messages.visible
import com.goterl.lazysodium.BuildConfig
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.Message
import org.session.libsession.messaging.messages.copyExpiration
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsignal.protos.SignalServiceProtos
import org.session.libsignal.utilities.Log
import org.session.libsession.messaging.sending_receiving.attachments.Attachment as SignalAttachment
/**
* @param syncTarget 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.
*/
data class VisibleMessage(
var syncTarget: String? = null,
var text: String? = null,
val attachmentIDs: MutableList<Long> = mutableListOf(),
var quote: Quote? = null,
var linkPreview: LinkPreview? = null,
var profile: Profile? = null,
var openGroupInvitation: OpenGroupInvitation? = null,
var reaction: Reaction? = null,
var hasMention: Boolean = false,
var blocksMessageRequests: Boolean = false
) : Message() {
override val isSelfSendValid: Boolean = true
// region Validation
override fun isValid(): Boolean {
if (!super.isValid()) return false
if (attachmentIDs.isNotEmpty()) return true
if (openGroupInvitation != null) return true
if (reaction != null) return true
val text = text?.trim() ?: return false
return text.isNotEmpty()
}
// endregion
// region Proto Conversion
companion object {
const val TAG = "VisibleMessage"
fun fromProto(proto: SignalServiceProtos.Content): VisibleMessage? =
proto.dataMessage?.let { VisibleMessage().apply {
if (it.hasSyncTarget()) syncTarget = it.syncTarget
text = it.body
// Attachments are handled in MessageReceiver
if (it.hasQuote()) quote = Quote.fromProto(it.quote)
linkPreview = it.previewList.firstOrNull()?.let(LinkPreview::fromProto)
if (it.hasOpenGroupInvitation()) openGroupInvitation = it.openGroupInvitation?.let(OpenGroupInvitation::fromProto)
// TODO Contact
profile = Profile.fromProto(it)
if (it.hasReaction()) reaction = it.reaction?.let(Reaction::fromProto)
blocksMessageRequests = it.hasBlocksCommunityMessageRequests() && it.blocksCommunityMessageRequests
}.copyExpiration(proto)
}
}
override fun toProto(): SignalServiceProtos.Content? {
val proto = SignalServiceProtos.Content.newBuilder()
// Profile
val dataMessage = profile?.toProto()?.toBuilder() ?: SignalServiceProtos.DataMessage.newBuilder()
// Text
if (text != null) { dataMessage.body = text }
// Quote
val quoteProto = quote?.toProto()
if (quoteProto != null) {
dataMessage.quote = quoteProto
}
// Reaction
val reactionProto = reaction?.toProto()
if (reactionProto != null) {
dataMessage.reaction = reactionProto
}
// Link preview
val linkPreviewProto = linkPreview?.toProto()
if (linkPreviewProto != null) {
dataMessage.addAllPreview(listOf(linkPreviewProto))
}
// Open group invitation
val openGroupInvitationProto = openGroupInvitation?.toProto()
if (openGroupInvitationProto != null) {
dataMessage.openGroupInvitation = openGroupInvitationProto
}
// Attachments
val database = MessagingModuleConfiguration.shared.messageDataProvider
val attachments = attachmentIDs.mapNotNull { database.getSignalAttachmentPointer(it) }
if (attachments.any { it.url.isNullOrEmpty() }) {
if (BuildConfig.DEBUG) {
Log.w(TAG, "Sending a message before all associated attachments have been uploaded.")
}
}
val pointers = attachments.mapNotNull { Attachment.createAttachmentPointer(it) }
dataMessage.addAllAttachments(pointers)
// TODO: Contact
// Expiration timer
proto.applyExpiryMode()
// Group context
val storage = MessagingModuleConfiguration.shared.storage
if (storage.isClosedGroup(recipient!!)) {
try {
dataMessage.setGroupContext()
} catch (e: Exception) {
Log.w(TAG, "Couldn't construct visible message proto from: $this")
return null
}
}
// Community blocked message requests flag
dataMessage.blocksCommunityMessageRequests = blocksMessageRequests
// Sync target
if (syncTarget != null) {
dataMessage.syncTarget = syncTarget
}
// Build
return try {
proto.dataMessage = dataMessage.build()
proto.build()
} catch (e: Exception) {
Log.w(TAG, "Couldn't construct visible message proto from: $this")
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 || reaction != null
}
}