From 96dadbaaa894118b5417bad4adb9deb46a255ac6 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 18 Sep 2019 17:33:34 +1000 Subject: [PATCH] Handle media message friend requests --- .../conversation/ConversationActivity.java | 4 ++ .../securesms/database/MmsDatabase.java | 16 ++++++++ .../securesms/jobs/PushDecryptJob.java | 17 +++++--- .../securesms/jobs/PushMediaSendJob.java | 39 +++++++++++++------ .../securesms/loki/FriendRequestView.kt | 3 -- .../securesms/mms/OutgoingMediaMessage.java | 1 + .../securesms/sms/MessageSender.java | 12 ++++++ .../securesms/sms/OutgoingTextMessage.java | 2 +- 8 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 0115a8d56e..8110fd00bc 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -2262,6 +2262,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity outgoingMessage = outgoingMessageCandidate; } + // Loki - Send a friend request if we're not yet friends with the user in question + LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadId); + outgoingMessage.isFriendRequest = (friendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS); // Needed for stageOutgoingMessage(...) + Permissions.with(this) .request(Manifest.permission.SEND_SMS, Manifest.permission.READ_SMS) .ifNecessary(!isSecureText || forceSms) diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index f3bb14dc4c..6fea8f244e 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -204,6 +204,22 @@ public class MmsDatabase extends MessagingDatabase { return 0; } + public long getIDForMessageAtIndex(long threadID, int index) { + SQLiteDatabase database = databaseHelper.getReadableDatabase(); + Cursor cursor = null; + try { + cursor = database.query(TABLE_NAME, null, THREAD_ID + " = ?", new String[] { threadID + "" }, null, null, null); + if (cursor != null && cursor.moveToPosition(index)) { + return cursor.getLong(0); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return -1; + } + public void addFailures(long messageId, List failure) { try { addToDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureList.class); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 286ceab5bb..1d9bf993aa 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -1052,9 +1052,10 @@ public class PushDecryptJob extends BaseJob implements InjectableType { LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context); long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(contactID); LokiThreadFriendRequestStatus threadFriendRequestStatus = lokiThreadDatabase.getFriendRequestStatus(threadID); - SmsDatabase messageDatabase = DatabaseFactory.getSmsDatabase(context); + SmsDatabase smsMessageDatabase = DatabaseFactory.getSmsDatabase(context); + MmsDatabase mmsMessageDatabase = DatabaseFactory.getMmsDatabase(context); LokiMessageDatabase lokiMessageDatabase= DatabaseFactory.getLokiMessageDatabase(context); - int messageCount = messageDatabase.getMessageCountForThread(threadID); + int messageCount = smsMessageDatabase.getMessageCountForThread(threadID); if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) { // This can happen if Alice sent Bob a friend request, Bob declined, but then Bob changed his // mind and sent a friend request to Alice. In this case we want Alice to auto-accept the request @@ -1067,7 +1068,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // we can end up in a deadlock where both users' threads' friend request statuses are // `REQUEST_SENT`. lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS); - long messageID = messageDatabase.getIDForMessageAtIndex(threadID, messageCount - 2); // The message before the one that was just received + long messageID = smsMessageDatabase.getIDForMessageAtIndex(threadID, messageCount - 2); // The message before the one that was just received + // TODO: MMS lokiMessageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED); // Accept the friend request sendBackgroundMessage(content.getSender()); @@ -1078,8 +1080,13 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // request. Alice's thread's friend request status is reset to // `REQUEST_RECEIVED`. lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_RECEIVED); - long messageID = messageDatabase.getIDForMessageAtIndex(threadID, messageCount - 1); // The message that was just received - lokiMessageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING); + long messageID = smsMessageDatabase.getIDForMessageAtIndex(threadID, messageCount - 1); // The message that was just received + if (messageID != -1) { + lokiMessageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING); + } else { + // TODO: The code below is ugly due to Java limitations + lokiMessageDatabase.setFriendRequestStatus(mmsMessageDatabase.getIDForMessageAtIndex(threadID, 0), LokiMessageFriendRequestStatus.REQUEST_PENDING); + } } } diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 50ec0fa8e1..0556817c11 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.libsignal.state.PreKeyBundle; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.SignalServiceMessageSender; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair; @@ -40,6 +41,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSy import org.whispersystems.signalservice.api.messages.shared.SharedContact; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException; +import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus; import java.io.FileNotFoundException; import java.io.IOException; @@ -122,6 +124,8 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); OutgoingMediaMessage message = database.getOutgoingMessage(messageId); + message.isFriendRequest = (DatabaseFactory.getLokiMessageDatabase(context).getFriendRequestStatus(messageId) == LokiMessageFriendRequestStatus.REQUEST_SENDING); + if (database.isSent(messageId)) { warn(TAG, "Message " + messageId + " was already sent. Ignoring."); return; @@ -210,18 +214,29 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { Optional sticker = getStickerFor(message); List sharedContacts = getSharedContactsFor(message); List previews = getPreviewsFor(message); - SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder() - .withBody(message.getBody()) - .withAttachments(serviceAttachments) - .withTimestamp(message.getSentTimeMillis()) - .withExpiration((int)(message.getExpiresIn() / 1000)) - .withProfileKey(profileKey.orNull()) - .withQuote(quote.orNull()) - .withSticker(sticker.orNull()) - .withSharedContacts(sharedContacts) - .withPreviews(previews) - .asExpirationUpdate(message.isExpirationUpdate()) - .build(); + + // Loki - Include a pre key bundle if the message is a friend request or an end session message + PreKeyBundle preKeyBundle; + if (message.isFriendRequest) { + preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(address.getNumber()); + } else { + preKeyBundle = null; + } + + SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder() + .withBody(message.getBody()) + .withAttachments(serviceAttachments) + .withTimestamp(message.getSentTimeMillis()) + .withExpiration((int)(message.getExpiresIn() / 1000)) + .withProfileKey(profileKey.orNull()) + .withQuote(quote.orNull()) + .withSticker(sticker.orNull()) + .withSharedContacts(sharedContacts) + .withPreviews(previews) + .asExpirationUpdate(message.isExpirationUpdate()) + .withPreKeyBundle(preKeyBundle) + .asFriendRequest(message.isFriendRequest) + .build(); if (address.getNumber().equals(TextSecurePreferences.getLocalNumber(context))) { Optional syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); diff --git a/src/org/thoughtcrime/securesms/loki/FriendRequestView.kt b/src/org/thoughtcrime/securesms/loki/FriendRequestView.kt index 6bacb7b46b..13c41eda49 100644 --- a/src/org/thoughtcrime/securesms/loki/FriendRequestView.kt +++ b/src/org/thoughtcrime/securesms/loki/FriendRequestView.kt @@ -12,7 +12,6 @@ import android.widget.TextView import network.loki.messenger.R import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.model.MessageRecord -import org.thoughtcrime.securesms.database.model.SmsMessageRecord import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus class FriendRequestView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) { @@ -108,8 +107,6 @@ class FriendRequestView(context: Context, attrs: AttributeSet?, defStyleAttr: In val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) val contactID = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(message!!.threadId)!!.address.toString() val contactDisplayName = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(contactID) ?: contactID - val isTextMessage = message is SmsMessageRecord - if (!isTextMessage) { visibility = View.GONE; return } val friendRequestStatus = lokiMessageDatabase.getFriendRequestStatus(message.id) if (!message.isOutgoing) { visibility = if (friendRequestStatus == LokiMessageFriendRequestStatus.NONE) View.GONE else View.VISIBLE diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java index 091c2e81fc..de1f2c9240 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java @@ -23,6 +23,7 @@ public class OutgoingMediaMessage { private final int distributionType; private final int subscriptionId; private final long expiresIn; + public boolean isFriendRequest = false; private final QuoteModel outgoingQuote; private final List networkFailures = new LinkedList<>(); diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index 1b939307e2..a6349f2e63 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -117,6 +117,10 @@ public class MessageSender { try { message.getAttachments().add(attachment); long messageID = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); + // Loki - Set the message's friend request status as soon as it has hit the database + if (message.isFriendRequest) { + DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_SENDING); + } sendMediaMessage(context, recipient, forceSms, messageID, message.getExpiresIn()); } catch (Exception e) { Log.w(TAG, e); @@ -125,6 +129,10 @@ public class MessageSender { } else { try { long messageID = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); + // Loki - Set the message's friend request status as soon as it has hit the database + if (message.isFriendRequest) { + DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_SENDING); + } sendMediaMessage(context, recipient, forceSms, messageID, message.getExpiresIn()); } catch (MmsException e) { Log.w(TAG, e); @@ -135,6 +143,10 @@ public class MessageSender { } else { try { long messageID = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); + // Loki - Set the message's friend request status as soon as it has hit the database + if (message.isFriendRequest) { + DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_SENDING); + } sendMediaMessage(context, recipient, forceSms, messageID, message.getExpiresIn()); } catch (MmsException e) { Log.w(TAG, e); diff --git a/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java b/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java index 5c3de47b5a..387fec8fa1 100644 --- a/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java +++ b/src/org/thoughtcrime/securesms/sms/OutgoingTextMessage.java @@ -9,7 +9,7 @@ public class OutgoingTextMessage { private final String message; private final int subscriptionId; private final long expiresIn; - public boolean isFriendRequest = false; + public boolean isFriendRequest = false; public OutgoingTextMessage(Recipient recipient, String message, int subscriptionId) { this(recipient, message, 0, subscriptionId);