diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
index beb5eb4aa8..b2f293ff25 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt
@@ -9,6 +9,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.*
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.UploadResult
import org.session.libsession.utilities.Util
+import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.messages.SignalServiceAttachment
import org.session.libsignal.messages.SignalServiceAttachmentPointer
import org.session.libsignal.messages.SignalServiceAttachmentStream
@@ -92,6 +93,14 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
return message.linkPreviews.firstOrNull()?.attachmentId?.rowId
}
+ override fun getIndividualRecipientForMms(mmsId: Long): Recipient? {
+ val mmsDb = DatabaseFactory.getMmsDatabase(context)
+ val message = mmsDb.getMessage(mmsId).use {
+ mmsDb.readerFor(it).next
+ }
+ return message?.individualRecipient
+ }
+
override fun insertAttachment(messageId: Long, attachmentId: AttachmentId, stream: InputStream) {
val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context)
attachmentDatabase.insertAttachmentsForPlaceholder(messageId, attachmentId, stream)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
index eeb9deacab..defdadf38d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt
@@ -89,6 +89,7 @@ import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
import org.thoughtcrime.securesms.conversation.v2.search.SearchBottomBar
import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel
import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager
+import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.DraftDatabase
import org.thoughtcrime.securesms.database.DraftDatabase.Drafts
@@ -255,6 +256,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
push(intent, false)
}
+ override fun showDialog(baseDialog: BaseDialog, tag: String?) {
+ baseDialog.show(supportFragmentManager, tag)
+ }
+
private fun setUpRecyclerView() {
conversationRecyclerView.adapter = adapter
val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt
index 553d061650..b4d4ab3941 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/AlbumThumbnailView.kt
@@ -15,6 +15,7 @@ import kotlinx.android.synthetic.main.album_thumbnail_view.view.*
import network.loki.messenger.R
import org.session.libsession.messaging.jobs.AttachmentDownloadJob
import org.session.libsession.messaging.jobs.JobQueue
+import org.session.libsession.messaging.sending_receiving.attachments.AttachmentTransferProgress
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.utilities.ViewUtil
import org.session.libsession.utilities.recipients.Recipient
@@ -86,7 +87,7 @@ class AlbumThumbnailView : FrameLayout {
// hit intersects with this particular child
val slide = slides.getOrNull(index) ?: return
// only open to downloaded images
- if (slide.isPendingDownload) {
+ if (slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED) {
// restart download here
(slide.asAttachment() as? DatabaseAttachment)?.let { attachment ->
val attachmentId = attachment.attachmentId.rowId
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt
index fe0423e2e2..fe8cbfcd69 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt
@@ -9,6 +9,7 @@ import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.dialog_download.view.*
import network.loki.messenger.R
import org.session.libsession.messaging.contacts.Contact
+import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
import org.thoughtcrime.securesms.database.DatabaseFactory
@@ -36,6 +37,12 @@ class DownloadDialog(private val recipient: Recipient) : BaseDialog() {
}
private fun trust() {
- // TODO: Implement
+ val contactDB = DatabaseFactory.getSessionContactDatabase(requireContext())
+ val sessionID = recipient.address.toString()
+ val contact = contactDB.getContactWithSessionID(sessionID) ?: return
+ val threadID = DatabaseFactory.getThreadDatabase(requireContext()).getThreadIdIfExistsFor(recipient)
+ contactDB.setContactIsTrusted(contact, true, threadID)
+ JobQueue.shared.resumePendingJobs()
+ dismiss()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/UntrustedAttachmentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/UntrustedAttachmentView.kt
new file mode 100644
index 0000000000..7f286a88e7
--- /dev/null
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/UntrustedAttachmentView.kt
@@ -0,0 +1,55 @@
+package org.thoughtcrime.securesms.conversation.v2.messages
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import androidx.annotation.ColorInt
+import androidx.core.content.ContextCompat
+import kotlinx.android.synthetic.main.view_untrusted_attachment.view.*
+import network.loki.messenger.R
+import org.session.libsession.utilities.recipients.Recipient
+import org.thoughtcrime.securesms.conversation.v2.dialogs.DownloadDialog
+import org.thoughtcrime.securesms.loki.utilities.ActivityDispatcher
+import java.util.*
+
+class UntrustedAttachmentView: LinearLayout {
+
+ enum class AttachmentType {
+ AUDIO,
+ DOCUMENT,
+ MEDIA
+ }
+
+ // region Lifecycle
+ constructor(context: Context) : super(context) { initialize() }
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() }
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() }
+
+ private fun initialize() {
+ LayoutInflater.from(context).inflate(R.layout.view_untrusted_attachment, this)
+ }
+ // endregion
+
+ // region Updating
+ fun bind(attachmentType: AttachmentType, @ColorInt textColor: Int) {
+ val (iconRes, stringRes) = when (attachmentType) {
+ AttachmentType.AUDIO -> R.drawable.ic_microphone to R.string.Slide_audio
+ AttachmentType.DOCUMENT -> R.drawable.ic_document_large_light to R.string.document
+ AttachmentType.MEDIA -> R.drawable.ic_image_white_24dp to R.string.media
+ }
+ val iconDrawable = ContextCompat.getDrawable(context,iconRes)!!
+ iconDrawable.mutate().setTint(textColor)
+ val text = context.getString(R.string.UntrustedAttachmentView_download_attachment, context.getString(stringRes).toLowerCase(Locale.ROOT))
+
+ untrustedAttachmentIcon.setImageDrawable(iconDrawable)
+ untrustedAttachmentTitle.text = text
+ }
+ // endregion
+
+ // region Interaction
+ fun showTrustDialog(recipient: Recipient) {
+ ActivityDispatcher.get(context)?.showDialog(DownloadDialog(recipient))
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
index dd111d0a72..1a9f2d01e2 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt
@@ -61,7 +61,7 @@ class VisibleMessageContentView : LinearLayout {
// region Updating
fun bind(message: MessageRecord, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean,
- glide: GlideRequests, maxWidth: Int, thread: Recipient, searchQuery: String?) {
+ glide: GlideRequests, maxWidth: Int, thread: Recipient, searchQuery: String?, contactIsTrusted: Boolean) {
// Background
val background = getBackground(message.isOutgoing, isStartOfMessageCluster, isEndOfMessageCluster)
val colorID = if (message.isOutgoing) R.attr.message_sent_background_color else R.attr.message_received_background_color
@@ -106,30 +106,54 @@ class VisibleMessageContentView : LinearLayout {
}
}
} else if (message is MmsMessageRecord && message.slideDeck.audioSlide != null) {
- val voiceMessageView = VoiceMessageView(context)
- voiceMessageView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster)
- mainContainer.addView(voiceMessageView)
- // We have to use onContentClick (rather than a click listener directly on the voice
- // message view) so as to not interfere with all the other gestures.
- onContentClick = { voiceMessageView.togglePlayback() }
- onContentDoubleTap = { voiceMessageView.handleDoubleTap() }
+ // Audio attachment
+ if (contactIsTrusted || message.isOutgoing) {
+ val voiceMessageView = VoiceMessageView(context)
+ voiceMessageView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster)
+ mainContainer.addView(voiceMessageView)
+ // We have to use onContentClick (rather than a click listener directly on the voice
+ // message view) so as to not interfere with all the other gestures.
+ onContentClick = { voiceMessageView.togglePlayback() }
+ onContentDoubleTap = { voiceMessageView.handleDoubleTap() }
+ } else {
+ val untrustedView = UntrustedAttachmentView(context)
+ untrustedView.bind(UntrustedAttachmentView.AttachmentType.AUDIO, VisibleMessageContentView.getTextColor(context,message))
+ mainContainer.addView(untrustedView)
+ onContentClick = { untrustedView.showTrustDialog(message.individualRecipient) }
+ }
} else if (message is MmsMessageRecord && message.slideDeck.documentSlide != null) {
- val documentView = DocumentView(context)
- documentView.bind(message, VisibleMessageContentView.getTextColor(context, message))
- mainContainer.addView(documentView)
+ // Document attachment
+ if (contactIsTrusted || message.isOutgoing) {
+ val documentView = DocumentView(context)
+ documentView.bind(message, VisibleMessageContentView.getTextColor(context, message))
+ mainContainer.addView(documentView)
+ } else {
+ val untrustedView = UntrustedAttachmentView(context)
+ untrustedView.bind(UntrustedAttachmentView.AttachmentType.DOCUMENT, VisibleMessageContentView.getTextColor(context,message))
+ mainContainer.addView(untrustedView)
+ onContentClick = { untrustedView.showTrustDialog(message.individualRecipient) }
+ }
} else if (message is MmsMessageRecord && message.slideDeck.asAttachments().isNotEmpty()) {
- val albumThumbnailView = AlbumThumbnailView(context)
- mainContainer.addView(albumThumbnailView)
- // isStart and isEnd of cluster needed for calculating the mask for full bubble image groups
- // bind after add view because views are inflated and calculated during bind
- albumThumbnailView.bind(
- glideRequests = glide,
- message = message,
- isStart = isStartOfMessageCluster,
- isEnd = isEndOfMessageCluster
- )
- onContentClick = { event ->
- albumThumbnailView.calculateHitObject(event, message, thread)
+ // Images/Video attachment
+ if (contactIsTrusted || message.isOutgoing) {
+ val albumThumbnailView = AlbumThumbnailView(context)
+ mainContainer.addView(albumThumbnailView)
+ // isStart and isEnd of cluster needed for calculating the mask for full bubble image groups
+ // bind after add view because views are inflated and calculated during bind
+ albumThumbnailView.bind(
+ glideRequests = glide,
+ message = message,
+ isStart = isStartOfMessageCluster,
+ isEnd = isEndOfMessageCluster
+ )
+ onContentClick = { event ->
+ albumThumbnailView.calculateHitObject(event, message, thread)
+ }
+ } else {
+ val untrustedView = UntrustedAttachmentView(context)
+ untrustedView.bind(UntrustedAttachmentView.AttachmentType.MEDIA, VisibleMessageContentView.getTextColor(context,message))
+ mainContainer.addView(untrustedView)
+ onContentClick = { untrustedView.showTrustDialog(message.individualRecipient) }
}
} else if (message.isOpenGroupInvitation) {
val openGroupInvitationView = OpenGroupInvitationView(context)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
index ad90bd5328..86b92b9498 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt
@@ -84,6 +84,7 @@ class VisibleMessageView : LinearLayout {
val threadDB = DatabaseFactory.getThreadDatabase(context)
val thread = threadDB.getRecipientForThreadId(threadID)!!
val contactDB = DatabaseFactory.getSessionContactDatabase(context)
+ val contact = contactDB.getContactWithSessionID(senderSessionID)
val isGroupThread = thread.isGroupRecipient
val isStartOfMessageCluster = isStartOfMessageCluster(message, previous, isGroupThread)
val isEndOfMessageCluster = isEndOfMessageCluster(message, next, isGroupThread)
@@ -103,7 +104,7 @@ class VisibleMessageView : LinearLayout {
}
senderNameTextView.isVisible = isStartOfMessageCluster
val context = if (thread.isOpenGroupRecipient) ContactContext.OPEN_GROUP else ContactContext.REGULAR
- senderNameTextView.text = contactDB.getContactWithSessionID(senderSessionID)?.displayName(context) ?: senderSessionID
+ senderNameTextView.text = contact?.displayName(context) ?: senderSessionID
} else {
profilePictureContainer.visibility = View.GONE
senderNameTextView.visibility = View.GONE
@@ -151,7 +152,7 @@ class VisibleMessageView : LinearLayout {
var maxWidth = screenWidth - startPadding - endPadding
if (profilePictureContainer.visibility != View.GONE) { maxWidth -= profilePictureContainer.width }
// Populate content view
- messageContentView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster, glide, maxWidth, thread, searchQuery)
+ messageContentView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster, glide, maxWidth, thread, searchQuery, isGroupThread || (contact?.isTrusted ?: false))
messageContentView.delegate = contentViewDelegate
onDoubleTap = { messageContentView.onContentDoubleTap?.invoke() }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/KThumbnailView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/KThumbnailView.kt
index 031aea1bad..80b233c42d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/KThumbnailView.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/utilities/KThumbnailView.kt
@@ -109,8 +109,8 @@ open class KThumbnailView: FrameLayout {
this.slide = slide
- loadIndicator.isVisible = slide.isInProgress && !slide.isPendingDownload
- downloadIndicator.isVisible = slide.isPendingDownload
+ loadIndicator.isVisible = slide.isInProgress
+ downloadIndicator.isVisible = slide.transferState == AttachmentTransferProgress.TRANSFER_PROGRESS_FAILED
dimensDelegate.setDimens(naturalWidth, naturalHeight)
invalidate()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
index 7fe982a9e3..85d1586a1b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt
@@ -505,9 +505,9 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
val mmsDb = DatabaseFactory.getMmsDatabase(context)
val cursor = mmsDb.getMessage(mmsId)
val reader = mmsDb.readerFor(cursor)
- val threadId = reader.next.threadId
+ val threadId = reader.next?.threadId
cursor.close()
- return threadId
+ return threadId ?: -1
}
override fun getContactWithSessionID(sessionID: String): Contact? {
@@ -522,6 +522,10 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
DatabaseFactory.getSessionContactDatabase(context).setContact(contact)
}
+ override fun getRecipientForThread(threadId: Long): Recipient? {
+ return DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId)
+ }
+
override fun getRecipientSettings(address: Address): Recipient.RecipientSettings? {
val recipientSettings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(address)
return if (recipientSettings.isPresent) { recipientSettings.get() } else null
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/database/SessionContactDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/database/SessionContactDatabase.kt
index 5ccb58df92..4429289f52 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/database/SessionContactDatabase.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/database/SessionContactDatabase.kt
@@ -47,11 +47,14 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
}.toSet()
}
- fun setContactIsTrusted(contact: Contact, isTrusted: Boolean) {
+ fun setContactIsTrusted(contact: Contact, isTrusted: Boolean, threadID: Long) {
val database = databaseHelper.writableDatabase
val contentValues = ContentValues(1)
contentValues.put(Companion.isTrusted, if (isTrusted) 1 else 0)
- database.insertOrUpdate(sessionContactTable, contentValues, "$sessionID = ?", arrayOf( contact.sessionID ))
+ database.update(sessionContactTable, contentValues, "$sessionID = ?", arrayOf( contact.sessionID ))
+ if (threadID >= 0) {
+ notifyConversationListeners(threadID)
+ }
notifyConversationListListeners()
}
@@ -66,7 +69,7 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
contact.profilePictureEncryptionKey?.let {
contentValues.put(profilePictureEncryptionKey, Base64.encodeBytes(it))
}
- contentValues.put(threadID, threadID)
+ contentValues.put(threadID, contact.threadID)
contentValues.put(isTrusted, if (contact.isTrusted) 1 else 0)
database.insertOrUpdate(sessionContactTable, contentValues, "$sessionID = ?", arrayOf( contact.sessionID ))
notifyConversationListListeners()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/ActivityUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/ActivityUtilities.kt
index 4986a1ce36..fbddffa5db 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/ActivityUtilities.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/ActivityUtilities.kt
@@ -10,6 +10,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import network.loki.messenger.R
import org.thoughtcrime.securesms.BaseActionBarActivity
+import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
fun BaseActionBarActivity.setUpActionBarSessionLogo(hideBackButton: Boolean = false) {
val actionbar = supportActionBar!!
@@ -65,4 +66,5 @@ interface ActivityDispatcher {
fun get(context: Context) = context.getSystemService(SERVICE) as? ActivityDispatcher
}
fun dispatchIntent(body: (Context)->Intent?)
+ fun showDialog(baseDialog: BaseDialog, tag: String? = null)
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_untrusted_attachment.xml b/app/src/main/res/layout/view_untrusted_attachment.xml
new file mode 100644
index 0000000000..c019dc1ace
--- /dev/null
+++ b/app/src/main/res/layout/view_untrusted_attachment.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8d31dbcf6e..1f11b6e3f7 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -874,4 +874,6 @@
%s is blocked. Unblock them?
Failed to prepare attachment for sending.
+ Media
+ Tap to download %s
diff --git a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt
index ca29118878..ef804a6e98 100644
--- a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt
+++ b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt
@@ -3,6 +3,7 @@ package org.session.libsession.database
import org.session.libsession.messaging.sending_receiving.attachments.*
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.UploadResult
+import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.messages.SignalServiceAttachmentPointer
import org.session.libsignal.messages.SignalServiceAttachmentStream
import java.io.InputStream
@@ -29,4 +30,5 @@ interface MessageDataProvider {
fun getMessageBodyFor(timestamp: Long, author: String): String
fun getAttachmentIDsFor(messageID: Long): List
fun getLinkPreviewAttachmentIDFor(messageID: Long): Long?
+ fun getIndividualRecipientForMms(mmsId: Long): Recipient?
}
\ No newline at end of file
diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt
index 8a21e61513..9e3ac258b9 100644
--- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt
+++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt
@@ -139,6 +139,7 @@ interface StorageProtocol {
fun getContactWithSessionID(sessionID: String): Contact?
fun getAllContacts(): Set
fun setContact(contact: Contact)
+ fun getRecipientForThread(threadId: Long): Recipient?
fun getRecipientSettings(address: Address): RecipientSettings?
fun addContacts(contacts: List)
diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt
index 5cbb5d808b..ed08ed2a73 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt
@@ -17,6 +17,7 @@ import org.session.libsignal.utilities.Log
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
+import java.lang.NullPointerException
class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long) : Job {
override var delegate: JobDelegate? = null
@@ -26,6 +27,8 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
// Error
internal sealed class Error(val description: String) : Exception(description) {
object NoAttachment : Error("No such attachment.")
+ object NoThread: Error("Thread no longer exists")
+ object NoSender: Error("Thread recipient or sender does not exist")
}
// Settings
@@ -42,8 +45,12 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
override fun execute() {
val storage = MessagingModuleConfiguration.shared.storage
val messageDataProvider = MessagingModuleConfiguration.shared.messageDataProvider
+ val threadID = storage.getThreadIdForMms(databaseMessageID)
+
val handleFailure: (java.lang.Exception, attachmentId: AttachmentId?) -> Unit = { exception, attachment ->
if (exception == Error.NoAttachment
+ || exception == Error.NoThread
+ || exception == Error.NoSender
|| (exception is OnionRequestAPI.HTTPRequestFailedAtDestinationException && exception.statusCode == 400)) {
attachment?.let { id ->
messageDataProvider.setAttachmentState(AttachmentState.FAILED, id, databaseMessageID)
@@ -55,13 +62,34 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
this.handleFailure(exception)
}
}
+
+ if (threadID < 0) {
+ Log.e("Loki", "Thread doesn't exist for database message ID $databaseMessageID")
+ handleFailure(Error.NoThread, null)
+ return
+ }
+
+ val threadRecipient = storage.getRecipientForThread(threadID)
+ val sender = messageDataProvider.getIndividualRecipientForMms(databaseMessageID)
+ val contact = sender?.address?.let { storage.getContactWithSessionID(it.serialize()) }
+ if (threadRecipient == null || sender == null || contact == null) {
+ handleFailure(Error.NoSender, null)
+ return
+ }
+ if (!threadRecipient.isGroupRecipient && (!contact.isTrusted || storage.getUserPublicKey() != sender.address.serialize())) {
+ Log.e("Loki", "Thread isn't a group recipient, or contact isn't trusted or self-send")
+ return
+ }
+
var tempFile: File? = null
try {
val attachment = messageDataProvider.getDatabaseAttachment(attachmentID)
?: return handleFailure(Error.NoAttachment, null)
+ if (attachment.hasData()) {
+ Log.d("Loki", "The attachment $attachmentID already has data")
+ }
messageDataProvider.setAttachmentState(AttachmentState.STARTED, attachment.attachmentId, this.databaseMessageID)
tempFile = createTempFile()
- val threadID = storage.getThreadIdForMms(databaseMessageID)
val openGroupV2 = storage.getV2OpenGroup(threadID)
if (openGroupV2 == null) {
DownloadUtilities.downloadFile(tempFile, attachment.url)
@@ -94,7 +122,7 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
handleSuccess()
} catch (e: Exception) {
tempFile?.delete()
- return handleFailure(e)
+ return handleFailure(e,null)
}
}
diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/JobQueue.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/JobQueue.kt
index 9ced85b110..900be7b25d 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/jobs/JobQueue.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/JobQueue.kt
@@ -100,6 +100,23 @@ class JobQueue : JobDelegate {
Log.d("Loki", "resumed pending send message $id")
}
+ fun resumePendingJobs(typeKey: String) {
+ val allPendingJobs = MessagingModuleConfiguration.shared.storage.getAllPendingJobs(typeKey)
+ val pendingJobs = mutableListOf()
+ for ((id, job) in allPendingJobs) {
+ if (job == null) {
+ // Job failed to deserialize, remove it from the DB
+ handleJobFailedPermanently(id)
+ } else {
+ pendingJobs.add(job)
+ }
+ }
+ pendingJobs.sortedBy { it.id }.forEach { job ->
+ Log.i("Loki", "Resuming pending job of type: ${job::class.simpleName}.")
+ queue.offer(job) // Offer always called on unlimited capacity
+ }
+ }
+
fun resumePendingJobs() {
if (hasResumedPendingJobs) {
Log.d("Loki", "resumePendingJobs() should only be called once.")
@@ -114,20 +131,7 @@ class JobQueue : JobDelegate {
NotifyPNServerJob.KEY
)
allJobTypes.forEach { type ->
- val allPendingJobs = MessagingModuleConfiguration.shared.storage.getAllPendingJobs(type)
- val pendingJobs = mutableListOf()
- for ((id, job) in allPendingJobs) {
- if (job == null) {
- // Job failed to deserialize, remove it from the DB
- handleJobFailedPermanently(id)
- } else {
- pendingJobs.add(job)
- }
- }
- pendingJobs.sortedBy { it.id }.forEach { job ->
- Log.i("Loki", "Resuming pending job of type: ${job::class.simpleName}.")
- queue.offer(job) // Offer always called on unlimited capacity
- }
+ resumePendingJobs(type)
}
}
diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt
index 6c11a23415..cfbd5605bd 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt
@@ -221,17 +221,10 @@ fun MessageReceiver.handleVisibleMessage(message: VisibleMessage, proto: SignalS
val messageID = storage.persist(message, quoteModel, linkPreviews, message.groupPublicKey, openGroupID, attachments) ?: throw MessageReceiver.Error.DuplicateMessage
// Parse & persist attachments
// Start attachment downloads if needed
- val contact = message.sender?.let { address -> storage.getContactWithSessionID(address) }
storage.getAttachmentsForMessage(messageID).forEach { attachment ->
attachment.attachmentId?.let { id ->
- // if open group or self-send, then always download attachment
- val immediatelyDownload = !openGroupID.isNullOrEmpty() // open group
- || userPublicKey == message.sender // self-send
- || contact?.isTrusted == true // trusted contact
- if (immediatelyDownload) {
- val downloadJob = AttachmentDownloadJob(id.rowId, messageID)
- JobQueue.shared.add(downloadJob)
- }
+ val downloadJob = AttachmentDownloadJob(id.rowId, messageID)
+ JobQueue.shared.add(downloadJob)
}
}
val openGroupServerID = message.openGroupServerMessageID