diff --git a/res/values/strings.xml b/res/values/strings.xml
index 19dbde81f8..9ae054a6c2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -663,6 +663,9 @@
You reset the secure session.
%s reset the secure session.
Duplicate message.
+
+ This message could not be processed because it was sent from a newer version of Signal. You can ask your contact to send this message again after you update.
+
Stickers
@@ -700,6 +703,7 @@
Your safety number with %s has changed.
You marked verified
You marked unverified
+ Message could not be processed
Signal update
diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
index 3872472a6d..118989623e 100644
--- a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
+++ b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
@@ -31,6 +31,7 @@ public interface MmsSmsColumns {
protected static final long OUTGOING_CALL_TYPE = 2;
protected static final long MISSED_CALL_TYPE = 3;
protected static final long JOINED_TYPE = 4;
+ protected static final long UNSUPPORTED_MESSAGE_TYPE = 5;
protected static final long BASE_INBOX_TYPE = 20;
protected static final long BASE_OUTBOX_TYPE = 21;
@@ -142,6 +143,10 @@ public interface MmsSmsColumns {
return (type & BASE_TYPE_MASK) == JOINED_TYPE;
}
+ public static boolean isUnsupportedMessageType(long type) {
+ return (type & BASE_TYPE_MASK) == UNSUPPORTED_MESSAGE_TYPE;
+ }
+
public static boolean isSecureType(long type) {
return (type & SECURE_MESSAGE_BIT) != 0;
}
diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java
index 9db2be22bc..3329e08ea3 100644
--- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java
@@ -217,6 +217,10 @@ public class SmsDatabase extends MessagingDatabase {
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_NO_SESSION_BIT);
}
+ public void markAsUnsupportedProtocolVersion(long id) {
+ updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.UNSUPPORTED_MESSAGE_TYPE);
+ }
+
public void markAsLegacyVersion(long id) {
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_LEGACY_BIT);
}
diff --git a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
index beede83f28..ea2e1d3af1 100644
--- a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
@@ -84,6 +84,8 @@ public class SmsMessageRecord extends MessageRecord {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_secure_session_reset));
} else if (isEndSession()) {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_secure_session_reset_s, getIndividualRecipient().toShortString()));
+ } else if (SmsDatabase.Types.isUnsupportedMessageType(type)) {
+ return emphasisAdded(context.getString(R.string.SmsMessageRecord_this_message_could_not_be_processed_because_it_was_sent_from_a_newer_version));
} else {
return super.getDisplayBody(context);
}
diff --git a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java
index 12a38cc253..57d84a895b 100644
--- a/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/ThreadRecord.java
@@ -109,6 +109,8 @@ public class ThreadRecord extends DisplayRecord {
return emphasisAdded(context.getString(R.string.ThreadRecord_you_marked_verified));
} else if (SmsDatabase.Types.isIdentityDefault(type)) {
return emphasisAdded(context.getString(R.string.ThreadRecord_you_marked_unverified));
+ } else if (SmsDatabase.Types.isUnsupportedMessageType(type)) {
+ return emphasisAdded(context.getString(R.string.ThreadRecord_message_could_not_be_processed));
} else {
if (TextUtils.isEmpty(getBody())) {
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_media_message)));
diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
index 86b292b997..986ba78f2b 100644
--- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java
@@ -117,6 +117,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.StickerPackOper
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
+import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
import java.security.MessageDigest;
import java.security.SecureRandom;
@@ -331,6 +332,9 @@ public class PushDecryptJob extends BaseJob {
Log.w(TAG, e);
} catch (SelfSendException e) {
Log.i(TAG, "Dropping UD message from self.");
+ } catch (UnsupportedDataMessageException e) {
+ Log.w(TAG, e);
+ handleUnsupportedDataMessage(e.getSender(), e.getSenderDevice(), e.getGroup(), envelope.getTimestamp(), smsMessageId);
}
}
@@ -1011,6 +1015,26 @@ public class PushDecryptJob extends BaseJob {
}
}
+ private void handleUnsupportedDataMessage(@NonNull String sender,
+ int senderDevice,
+ @NonNull Optional group,
+ long timestamp,
+ @NonNull Optional smsMessageId)
+ {
+ SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
+
+ if (!smsMessageId.isPresent()) {
+ Optional insertResult = insertPlaceholder(sender, senderDevice, timestamp, group);
+
+ if (insertResult.isPresent()) {
+ smsDatabase.markAsUnsupportedProtocolVersion(insertResult.get().getMessageId());
+ MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
+ }
+ } else {
+ smsDatabase.markAsNoSession(smsMessageId.get());
+ }
+ }
+
private void handleLegacyMessage(@NonNull String sender, int senderDevice, long timestamp,
@NonNull Optional smsMessageId)
{
@@ -1241,10 +1265,14 @@ public class PushDecryptJob extends BaseJob {
}
private Optional insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp) {
+ return insertPlaceholder(sender, senderDevice, timestamp, Optional.absent());
+ }
+
+ private Optional insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp, Optional group) {
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, sender),
senderDevice, timestamp, "",
- Optional.absent(), 0, false);
+ group, 0, false);
textMessage = new IncomingEncryptedMessage(textMessage, "");
return database.insertMessageInbox(textMessage);