Merge pull request #443 from RyanRory/multi_device_refactor

The Refactor: Multi Device & Closed Group
This commit is contained in:
Niels Andriesse
2021-02-19 13:49:06 +11:00
committed by GitHub
28 changed files with 436 additions and 294 deletions

View File

@@ -8,6 +8,8 @@ import org.session.libsession.messaging.sending_receiving.attachments.*
import org.session.libsession.messaging.threads.Address
import org.session.libsignal.libsignal.util.guava.Optional
import org.session.libsignal.service.api.messages.SignalServiceAttachment
import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
import org.session.libsignal.service.api.messages.SignalServiceAttachmentStream
import org.thoughtcrime.securesms.database.Database
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
@@ -32,6 +34,18 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
return databaseAttachment.toAttachmentPointer()
}
override fun getSignalAttachmentStream(attachmentId: Long): SignalServiceAttachmentStream? {
val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context)
val databaseAttachment = attachmentDatabase.getAttachment(AttachmentId(attachmentId, 0)) ?: return null
return databaseAttachment.toSignalAttachmentStream(context)
}
override fun getSignalAttachmentPointer(attachmentId: Long): SignalServiceAttachmentPointer? {
val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context)
val databaseAttachment = attachmentDatabase.getAttachment(AttachmentId(attachmentId, 0)) ?: return null
return databaseAttachment.toSignalAttachmentPointer()
}
override fun setAttachmentState(attachmentState: AttachmentState, attachmentId: Long, messageID: Long) {
val attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context)
attachmentDatabase.setTransferState(messageID, AttachmentId(attachmentId, 0), attachmentState.value)
@@ -103,6 +117,17 @@ fun DatabaseAttachment.toAttachmentStream(context: Context): SessionServiceAttac
return attachmentStream
}
fun DatabaseAttachment.toSignalAttachmentPointer(): SignalServiceAttachmentPointer {
return SignalServiceAttachmentPointer(attachmentId.rowId, contentType, key?.toByteArray(), Optional.fromNullable(size.toInt()), Optional.absent(), width, height, Optional.fromNullable(digest), Optional.fromNullable(fileName), isVoiceNote, Optional.fromNullable(caption), url)
}
fun DatabaseAttachment.toSignalAttachmentStream(context: Context): SignalServiceAttachmentStream {
val stream = PartAuthority.getAttachmentStream(context, this.dataUri!!)
val listener = SignalServiceAttachment.ProgressListener { total: Long, progress: Long -> EventBus.getDefault().postSticky(PartProgressEvent(this, total, progress))}
return SignalServiceAttachmentStream(stream, this.contentType, this.size, Optional.fromNullable(this.fileName), this.isVoiceNote, Optional.absent(), this.width, this.height, Optional.fromNullable(this.caption), listener)
}
fun DatabaseAttachment.shouldHaveImageSize(): Boolean {
return (MediaUtil.isVideo(this) || MediaUtil.isImage(this) || MediaUtil.isGif(this));
}

View File

@@ -136,7 +136,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
return cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID));
} else {
String groupId = GroupUtil.getEncodedMMSGroupID(allocateGroupId());
create(groupId, null, members, null, null, admins);
create(groupId, null, members, null, null, admins, System.currentTimeMillis());
return groupId;
}
} finally {
@@ -196,7 +196,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
}
public long create(@NonNull String groupId, @Nullable String title, @NonNull List<Address> members,
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay, @Nullable List<Address> admins)
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay, @Nullable List<Address> admins, @NonNull Long formationTimestamp)
{
Collections.sort(members);
@@ -214,7 +214,7 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
}
contentValues.put(AVATAR_RELAY, relay);
contentValues.put(TIMESTAMP, System.currentTimeMillis());
contentValues.put(TIMESTAMP, formationTimestamp);
contentValues.put(ACTIVE, 1);
contentValues.put(MMS, GroupUtil.isMmsGroup(groupId));

View File

@@ -905,6 +905,9 @@ public class MmsDatabase extends MessagingDatabase {
public Optional<InsertResult> insertSecureDecryptedMessageOutbox(OutgoingMediaMessage retrieved, long threadId, long serverTimestamp)
throws MmsException
{
if (threadId == -1) {
threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(retrieved.getRecipient());
}
long messageId = insertMessageOutbox(retrieved, threadId, false, null, serverTimestamp);
if (messageId == -1) {
return Optional.absent();

View File

@@ -78,6 +78,14 @@ public class MmsSmsDatabase extends Database {
super(context, databaseHelper);
}
public @Nullable MessageRecord getMessageForTimestamp(long timestamp) {
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);
try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null)) {
MmsSmsDatabase.Reader reader = db.readerFor(cursor);
return reader.getNext();
}
}
public @Nullable MessageRecord getMessageFor(long messageId) {
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);

View File

@@ -687,6 +687,9 @@ public class SmsDatabase extends MessagingDatabase {
}
public Optional<InsertResult> insertMessageOutbox(long threadId, OutgoingTextMessage message, long serverTimestamp) {
if (threadId == -1) {
threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(message.getRecipient());
}
long messageId = insertMessageOutbox(threadId, message, false, serverTimestamp, null);
if (messageId == -1) {
return Optional.absent();

View File

@@ -12,6 +12,8 @@ import org.session.libsession.messaging.messages.visible.Attachment
import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.opengroups.OpenGroup
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment
import org.session.libsession.messaging.sending_receiving.attachments.SessionServiceAttachment
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
import org.session.libsession.messaging.threads.Address
@@ -27,17 +29,21 @@ import org.session.libsignal.service.api.messages.SignalServiceAttachmentPointer
import org.session.libsignal.service.api.messages.SignalServiceGroup
import org.session.libsignal.service.internal.push.SignalServiceProtos
import org.session.libsignal.service.loki.api.opengroups.PublicChat
import org.session.libsignal.utilities.logging.Log
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.loki.database.LokiThreadDatabase
import org.thoughtcrime.securesms.loki.protocol.SessionMetaProtocol
import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities
import org.thoughtcrime.securesms.loki.utilities.get
import org.thoughtcrime.securesms.loki.utilities.getString
import org.thoughtcrime.securesms.mms.IncomingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.PartAuthority
import org.thoughtcrime.securesms.sms.IncomingGroupMessage
import org.thoughtcrime.securesms.sms.IncomingTextMessage
import org.thoughtcrime.securesms.sms.OutgoingTextMessage
class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol {
override fun getUserPublicKey(): String? {
@@ -90,9 +96,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
override fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List<LinkPreview?>, groupPublicKey: String?, openGroupID: String?): Long? {
var messageID: Long? = null
val address = Address.fromSerialized(message.sender!!)
val recipient = Recipient.from(context, address, false)
val body: Optional<String> = if (message.text != null) Optional.of(message.text) else Optional.absent()
val senderAddress = Address.fromSerialized(message.sender!!)
val senderRecipient = Recipient.from(context, senderAddress, false)
var group: Optional<SignalServiceGroup> = Optional.absent()
if (openGroupID != null) {
group = Optional.of(SignalServiceGroup(openGroupID.toByteArray(), SignalServiceGroup.GroupType.PUBLIC_CHAT))
@@ -100,17 +105,39 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
group = Optional.of(SignalServiceGroup(groupPublicKey.toByteArray(), SignalServiceGroup.GroupType.SIGNAL))
}
if (message.isMediaMessage()) {
val attachments: Optional<List<SignalServiceAttachment>> = Optional.absent() // TODO figure out how to get SignalServiceAttachment with attachmentID
val quote: Optional<QuoteModel> = if (quotes != null) Optional.of(quotes) else Optional.absent()
val linkPreviews: Optional<List<LinkPreview>> = if (linkPreview.isEmpty()) Optional.absent() else Optional.of(linkPreview.mapNotNull { it!! })
val mediaMessage = IncomingMediaMessage(address, message.receivedTimestamp!!, -1, recipient.expireMessages * 1000L, false, false, body, group, attachments, quote, Optional.absent(), linkPreviews, Optional.absent())
val mmsDatabase = DatabaseFactory.getMmsDatabase(context)
mmsDatabase.beginTransaction()
val insertResult: Optional<MessagingDatabase.InsertResult>
if (group.isPresent) {
insertResult = mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!);
val insertResult = if (message.sender == getUserPublicKey()) {
val targetAddress = if (message.syncTarget != null) {
Address.fromSerialized(message.syncTarget!!)
} else {
if (group.isPresent) {
Address.fromSerialized(GroupUtil.getEncodedId(group.get()))
} else {
Log.d("Loki", "Cannot handle message from self.")
return null
}
}
val attachments = message.attachmentIDs.mapNotNull {
DatabaseFactory.getAttachmentProvider(context).getSignalAttachmentPointer(it)
}.mapNotNull {
PointerAttachment.forPointer(Optional.of(it)).orNull()
}
val mediaMessage = OutgoingMediaMessage.from(message, Recipient.from(context, targetAddress, false), attachments, quote.orNull(), linkPreviews.orNull())
mmsDatabase.insertSecureDecryptedMessageOutbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!)
} else {
insertResult = mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1)
// It seems like we have replaced SignalServiceAttachment with SessionServiceAttachment
val attachments: Optional<List<SignalServiceAttachment>> = Optional.of(message.attachmentIDs.mapNotNull {
DatabaseFactory.getAttachmentProvider(context).getSignalAttachmentPointer(it)
})
val mediaMessage = IncomingMediaMessage.from(message, senderAddress, senderRecipient.expireMessages * 1000L, group, attachments, quote, linkPreviews)
if (group.isPresent) {
mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!)
} else {
mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1)
}
}
if (insertResult.isPresent) {
mmsDatabase.setTransactionSuccessful()
@@ -118,9 +145,28 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
mmsDatabase.endTransaction()
} else {
val textMessage = IncomingTextMessage(address, 1, message.receivedTimestamp!!, body.get(), group, recipient.expireMessages * 1000L, false)
val smsDatabase = DatabaseFactory.getSmsDatabase(context)
val insertResult = smsDatabase.insertMessageInbox(textMessage)
val insertResult = if (message.sender == getUserPublicKey()) {
val targetAddress = if (message.syncTarget != null) {
Address.fromSerialized(message.syncTarget!!)
} else {
if (group.isPresent) {
Address.fromSerialized(GroupUtil.getEncodedId(group.get()))
} else {
Log.d("Loki", "Cannot handle message from self.")
return null
}
}
val textMessage = OutgoingTextMessage.from(message, Recipient.from(context, targetAddress, false))
smsDatabase.insertMessageOutbox(message.threadID ?: -1, textMessage, message.sentTimestamp!!)
} else {
val textMessage = IncomingTextMessage.from(message, senderAddress, group, senderRecipient.expireMessages * 1000L)
if (group.isPresent) {
smsDatabase.insertMessageInbox(textMessage, message.sentTimestamp!!)
} else {
smsDatabase.insertMessageInbox(textMessage)
}
}
if (insertResult.isPresent) {
messageID = insertResult.get().messageId
}
@@ -129,7 +175,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
// JOBS
override fun persistJob(job: Job) {
DatabaseFactory.getSessionJobDatabase(context).persistJob(job)
}
@@ -235,6 +280,15 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
DatabaseFactory.getLokiAPIDatabase(context).removeLastDeletionServerID(group, server)
}
override fun isMessageDuplicated(timestamp: Long, sender: String): Boolean {
val database = DatabaseFactory.getMmsSmsDatabase(context)
return if (sender.isEmpty()) {
database.getMessageForTimestamp(timestamp) != null
} else {
database.getMessageFor(timestamp, sender) != null
}
}
override fun setUserCount(group: Long, server: String, newValue: Int) {
DatabaseFactory.getLokiAPIDatabase(context).setUserCount(group, server, newValue)
}
@@ -256,13 +310,17 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
}
override fun getReceivedMessageTimestamps(): Set<Long> {
TODO("Not yet implemented")
return SessionMetaProtocol.getTimestamps()
}
override fun addReceivedMessageTimestamp(timestamp: Long) {
TODO("Not yet implemented")
SessionMetaProtocol.addTimestamp(timestamp)
}
// override fun removeReceivedMessageTimestamps(timestamps: Set<Long>) {
// TODO("Not yet implemented")
// }
override fun getMessageIdInDatabase(timestamp: Long, author: String): Long? {
val database = DatabaseFactory.getMmsSmsDatabase(context)
val address = Address.fromSerialized(author)
@@ -314,8 +372,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
return if (group.isPresent) { group.get() } else null
}
override fun createGroup(groupId: String, title: String?, members: List<Address>, avatar: SignalServiceAttachmentPointer?, relay: String?, admins: List<Address>) {
DatabaseFactory.getGroupDatabase(context).create(groupId, title, members, avatar, relay, admins)
override fun createGroup(groupId: String, title: String?, members: List<Address>, avatar: SignalServiceAttachmentPointer?, relay: String?, admins: List<Address>, formationTimestamp: Long) {
DatabaseFactory.getGroupDatabase(context).create(groupId, title, members, avatar, relay, admins, formationTimestamp)
}
override fun setActive(groupID: String, value: Boolean) {

View File

@@ -77,7 +77,7 @@ public class GroupManager {
String masterPublicKey = masterPublicKeyOrNull != null ? masterPublicKeyOrNull : TextSecurePreferences.getLocalNumber(context);
memberAddresses.add(Address.Companion.fromSerialized(masterPublicKey));
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>(adminAddresses));
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>(adminAddresses), System.currentTimeMillis());
groupDatabase.updateProfilePicture(groupId, avatarBytes);
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient, true);
@@ -104,7 +104,7 @@ public class GroupManager {
final Set<Address> memberAddresses = new HashSet<>();
memberAddresses.add(Address.Companion.fromSerialized(Objects.requireNonNull(TextSecurePreferences.getLocalNumber(context))));
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>());
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null, new LinkedList<>(), System.currentTimeMillis());
groupDatabase.updateProfilePicture(groupId, avatarBytes);

View File

@@ -69,7 +69,7 @@ public class GroupMessageProcessor {
if (record.isPresent() && group.getType() == Type.UPDATE) {
return handleGroupUpdate(context, content, group, record.get(), outgoing);
} else if (!record.isPresent() && group.getType() == Type.UPDATE) {
return handleGroupCreate(context, content, group, outgoing);
return handleGroupCreate(context, content, group, outgoing, message.getTimestamp());
} else if (record.isPresent() && group.getType() == Type.QUIT) {
return handleGroupLeave(context, content, group, record.get(), outgoing);
} else if (record.isPresent() && group.getType() == Type.REQUEST_INFO) {
@@ -83,7 +83,8 @@ public class GroupMessageProcessor {
private static @Nullable Long handleGroupCreate(@NonNull Context context,
@NonNull SignalServiceContent content,
@NonNull SignalServiceGroup group,
boolean outgoing)
boolean outgoing,
Long formationTimestamp)
{
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
String id = GroupUtil.getEncodedId(group);
@@ -108,7 +109,7 @@ public class GroupMessageProcessor {
}
database.create(id, group.getName().orNull(), members,
avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null, admins);
avatar != null && avatar.isPointer() ? avatar.asPointer() : null, null, admins, formationTimestamp);
if (group.getMembers().isPresent()) {
ClosedGroupsProtocol.establishSessionsWithMembersIfNeeded(context, group.getMembers().get());

View File

@@ -69,7 +69,7 @@ object ClosedGroupsProtocolV2 {
val admins = setOf( userPublicKey )
val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
DatabaseFactory.getGroupDatabase(context).create(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }),
null, null, LinkedList(admins.map { Address.fromSerialized(it!!) }))
null, null, LinkedList(admins.map { Address.fromSerialized(it!!) }), System.currentTimeMillis())
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
// Send a closed group update message to all members individually
// Add the group to the user's set of public keys to poll for
@@ -463,7 +463,7 @@ object ClosedGroupsProtocolV2 {
groupDB.updateMembers(groupID, members.map { Address.fromSerialized(it) })
} else {
groupDB.create(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }),
null, null, LinkedList(admins.map { Address.fromSerialized(it) }))
null, null, LinkedList(admins.map { Address.fromSerialized(it) }), sentTimestamp)
}
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
// Add the group to the user's set of public keys to poll for
@@ -716,7 +716,7 @@ object ClosedGroupsProtocolV2 {
senderPublicKey: String): Boolean {
val oldMembers = group.members.map { it.serialize() }
// Check that the message isn't from before the group was created
if (group.createdAt > sentTimestamp) {
if (group.formationTimestamp > sentTimestamp) {
Log.d("Loki", "Ignoring closed group update from before thread was created.")
return false
}

View File

@@ -19,6 +19,7 @@ import java.util.*
object MultiDeviceProtocol {
// TODO: refactor this to use new message sending job
@JvmStatic
fun syncConfigurationIfNeeded(context: Context) {
val userPublicKey = TextSecurePreferences.getLocalNumber(context) ?: return
@@ -41,6 +42,7 @@ object MultiDeviceProtocol {
}
}
// TODO: refactor this to use new message sending job
fun forceSyncConfigurationNowIfNeeded(context: Context) {
val userPublicKey = TextSecurePreferences.getLocalNumber(context) ?: return
val configurationMessage = ConfigurationMessage.getCurrent()
@@ -58,6 +60,7 @@ object MultiDeviceProtocol {
}
}
// TODO: remove this after we migrate to new message receiving pipeline
@JvmStatic
fun handleConfigurationMessage(context: Context, content: SignalServiceProtos.Content, senderPublicKey: String, timestamp: Long) {
if (TextSecurePreferences.getConfigurationMessageSynced(context)) return

View File

@@ -21,6 +21,14 @@ object SessionMetaProtocol {
timestamps.remove(timestamp)
}
fun getTimestamps(): Set<Long> {
return timestamps
}
fun addTimestamp(timestamp: Long) {
timestamps.add(timestamp)
}
@JvmStatic
fun shouldIgnoreMessage(timestamp: Long): Boolean {
val shouldIgnoreMessage = timestamps.contains(timestamp)

View File

@@ -1,15 +1,18 @@
package org.thoughtcrime.securesms.mms;
import org.session.libsession.messaging.messages.visible.VisibleMessage;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.messaging.sending_receiving.attachments.PointerAttachment;
import org.session.libsession.messaging.sending_receiving.sharecontacts.Contact;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPreview;
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.messaging.threads.recipients.Recipient;
import org.session.libsession.utilities.GroupUtil;
import org.session.libsignal.libsignal.util.guava.Optional;
import org.session.libsignal.service.api.messages.SignalServiceAttachment;
import org.session.libsignal.service.api.messages.SignalServiceGroup;
import org.thoughtcrime.securesms.ApplicationContext;
import java.util.Collections;
import java.util.LinkedList;
@@ -92,6 +95,18 @@ public class IncomingMediaMessage {
}
}
public static IncomingMediaMessage from(VisibleMessage message,
Address from,
long expiresIn,
Optional<SignalServiceGroup> group,
Optional<List<SignalServiceAttachment>> attachments,
Optional<QuoteModel> quote,
Optional<List<LinkPreview>> linkPreviews)
{
return new IncomingMediaMessage(from, message.getReceivedTimestamp(), -1, expiresIn, false,
false, Optional.fromNullable(message.getText()), group, attachments, quote, Optional.absent(), linkPreviews, Optional.absent());
}
public int getSubscriptionId() {
return subscriptionId;
}

View File

@@ -4,6 +4,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import org.session.libsession.messaging.messages.visible.VisibleMessage;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
@@ -12,6 +14,7 @@ import org.session.libsession.messaging.sending_receiving.linkpreview.LinkPrevie
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel;
import org.session.libsession.messaging.threads.recipients.Recipient;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -86,6 +89,17 @@ public class OutgoingMediaMessage {
this.linkPreviews.addAll(that.linkPreviews);
}
public static OutgoingMediaMessage from(VisibleMessage message,
Recipient recipient,
List<Attachment> attachments,
@Nullable QuoteModel outgoingQuote,
@NonNull List<LinkPreview> linkPreviews)
{
return new OutgoingMediaMessage(recipient, message.getText(), attachments, message.getSentTimestamp(), -1,
recipient.getExpireMessages() * 1000, ThreadDatabase.DistributionTypes.DEFAULT, outgoingQuote, Collections.emptyList(),
linkPreviews, Collections.emptyList(), Collections.emptyList());
}
public Recipient getRecipient() {
return recipient;
}

View File

@@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.telephony.SmsMessage;
import org.session.libsession.messaging.messages.visible.VisibleMessage;
import org.session.libsession.messaging.threads.Address;
import org.session.libsession.utilities.GroupUtil;
import org.session.libsignal.libsignal.util.guava.Optional;
@@ -155,6 +156,14 @@ public class IncomingTextMessage implements Parcelable {
this.unidentified = false;
}
public static IncomingTextMessage from(VisibleMessage message,
Address sender,
Optional<SignalServiceGroup> group,
long expiresInMillis)
{
return new IncomingTextMessage(sender, 1, message.getReceivedTimestamp(), message.getText(), group, expiresInMillis, false);
}
public int getSubscriptionId() {
return subscriptionId;
}

View File

@@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.sms;
import org.session.libsession.messaging.messages.visible.VisibleMessage;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.session.libsession.messaging.threads.recipients.Recipient;
@@ -28,6 +29,10 @@ public class OutgoingTextMessage {
this.message = body;
}
public static OutgoingTextMessage from(VisibleMessage message, Recipient recipient) {
return new OutgoingTextMessage(recipient, message.getText(), recipient.getExpireMessages() * 1000, -1);
}
public long getExpiresIn() {
return expiresIn;
}