Remove sms/mms receive code.

Simplifying incoming message insert. Removing this dead path as part of
it.
This commit is contained in:
Greyson Parrelli
2023-10-23 13:28:34 -04:00
parent a4df433d80
commit d468d4c21b
9 changed files with 4 additions and 908 deletions

View File

@@ -1203,18 +1203,6 @@
</intent-filter>
</service>
<receiver android:name=".service.SmsListener"
android:permission="android.permission.BROADCAST_SMS"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="1001">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER"/>
</intent-filter>
</receiver>
<receiver android:name=".service.SmsDeliveryListener"
android:exported="true">
<intent-filter>
@@ -1222,20 +1210,6 @@
</intent-filter>
</receiver>
<receiver android:name=".service.MmsListener"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BROADCAST_WAP_PUSH">
<intent-filter android:priority="1001">
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED"/>
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER"/>
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
<receiver android:name=".notifications.MarkReadReceiver"
android:enabled="true"
android:exported="false">

View File

@@ -115,7 +115,6 @@ import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackPolicy;
import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackPolicyEnforcer;
import org.thoughtcrime.securesms.jobmanager.JobManager;
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
import org.thoughtcrime.securesms.jobs.MmsDownloadJob;
import org.thoughtcrime.securesms.jobs.MmsSendJob;
import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
@@ -2436,10 +2435,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
public void onClick(View v, final List<Slide> slides) {
Log.i(TAG, "onClick() for attachment download");
if (messageRecord.isMmsNotification()) {
Log.i(TAG, "Scheduling MMS attachment download");
ApplicationDependencies.getJobManager().add(new MmsDownloadJob(messageRecord.getId(),
messageRecord.getThreadId(),
false));
Log.w(TAG, "Ignoring MMS download.");
} else {
Log.i(TAG, "Scheduling push attachment downloads for " + slides.size() + " items");

View File

@@ -2789,39 +2789,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
return insertMessageInbox(retrieved, "", threadId, type, edittedMediaMessage, notifyObservers)
}
fun insertMessageInbox(notification: NotificationInd, subscriptionId: Int): Pair<Long, Long> {
Log.i(TAG, "Message received type: " + notification.messageType)
val threadId = getThreadIdFor(notification)
val authorId: String = if (notification.from != null) {
Recipient.external(context, Util.toIsoString(notification.from.textString)).id.serialize()
} else {
RecipientId.UNKNOWN.serialize()
}
val messageId = writableDatabase
.insertInto(TABLE_NAME)
.values(
MMS_CONTENT_LOCATION to notification.contentLocation.toIsoString(),
DATE_SENT to System.currentTimeMillis(),
MMS_EXPIRY to if (notification.expiry != -1L) notification.expiry else null,
MMS_MESSAGE_SIZE to if (notification.messageSize != -1L) notification.messageSize else null,
MMS_TRANSACTION_ID to notification.transactionId.toIsoString(),
MMS_MESSAGE_TYPE to if (notification.messageType != 0) notification.messageType else null,
FROM_RECIPIENT_ID to authorId,
TYPE to MessageTypes.BASE_INBOX_TYPE,
THREAD_ID to threadId,
MMS_STATUS to MmsStatus.DOWNLOAD_INITIALIZED,
DATE_RECEIVED to generatePduCompatTimestamp(System.currentTimeMillis()),
READ to if (Util.isDefaultSmsProvider(context)) 0 else 1,
SMS_SUBSCRIPTION_ID to subscriptionId
)
.run(SQLiteDatabase.CONFLICT_IGNORE)
return Pair(messageId, threadId)
}
fun insertChatSessionRefreshedMessage(recipientId: RecipientId, senderDeviceId: Long, sentTimestamp: Long): InsertResult {
val threadId = threads.getOrCreateThreadIdFor(Recipient.resolved(recipientId))
var type = MessageTypes.SECURE_MESSAGE_BIT or MessageTypes.PUSH_MESSAGE_BIT

View File

@@ -135,8 +135,6 @@ public final class JobManagerFactories {
put(LocalBackupJob.KEY, new LocalBackupJob.Factory());
put(LocalBackupJobApi29.KEY, new LocalBackupJobApi29.Factory());
put(MarkerJob.KEY, new MarkerJob.Factory());
put(MmsDownloadJob.KEY, new MmsDownloadJob.Factory());
put(MmsReceiveJob.KEY, new MmsReceiveJob.Factory());
put(MmsSendJob.KEY, new MmsSendJob.Factory());
put(MultiDeviceBlockedUpdateJob.KEY, new MultiDeviceBlockedUpdateJob.Factory());
put(MultiDeviceCallLinkSyncJob.KEY, new MultiDeviceCallLinkSyncJob.Factory());
@@ -204,7 +202,6 @@ public final class JobManagerFactories {
put(MultiDeviceStorySendSyncJob.KEY, new MultiDeviceStorySendSyncJob.Factory());
put(ResetSvrGuessCountJob.KEY, new ResetSvrGuessCountJob.Factory());
put(ServiceOutageDetectionJob.KEY, new ServiceOutageDetectionJob.Factory());
put(SmsReceiveJob.KEY, new SmsReceiveJob.Factory());
put(SmsSendJob.KEY, new SmsSendJob.Factory());
put(SmsSentJob.KEY, new SmsSentJob.Factory());
put(StickerDownloadJob.KEY, new StickerDownloadJob.Factory());
@@ -303,6 +300,9 @@ public final class JobManagerFactories {
put("PushDecryptDrainedJob", new FailingJob.Factory());
put("PushProcessJob", new FailingJob.Factory());
put("DecryptionsDrainedMigrationJob", new PassingMigrationJob.Factory());
put("MmsReceiveJob", new FailingJob.Factory());
put("MmsDownloadJob", new FailingJob.Factory());
put("SmsReceiveJob", new FailingJob.Factory());
}};
}

View File

@@ -1,285 +0,0 @@
package org.thoughtcrime.securesms.jobs;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.mms.pdu_alt.CharacterSets;
import com.google.android.mms.pdu_alt.EncodedStringValue;
import com.google.android.mms.pdu_alt.PduBody;
import com.google.android.mms.pdu_alt.PduPart;
import com.google.android.mms.pdu_alt.RetrieveConf;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.UriAttachment;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.contactshare.VCardUtil;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.database.MessageTable;
import org.thoughtcrime.securesms.database.MessageTable.InsertResult;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.MmsRadioException;
import org.thoughtcrime.securesms.mms.PartParser;
import org.thoughtcrime.securesms.notifications.v2.ConversationId;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class MmsDownloadJob extends BaseJob {
public static final String KEY = "MmsDownloadJob";
private static final String TAG = Log.tag(MmsDownloadJob.class);
private static final String KEY_MESSAGE_ID = "message_id";
private static final String KEY_THREAD_ID = "thread_id";
private static final String KEY_AUTOMATIC = "automatic";
private long messageId;
private long threadId;
private boolean automatic;
public MmsDownloadJob(long messageId, long threadId, boolean automatic) {
this(new Job.Parameters.Builder()
.setQueue("mms-operation")
.setMaxAttempts(25)
.build(),
messageId,
threadId,
automatic);
}
private MmsDownloadJob(@NonNull Job.Parameters parameters, long messageId, long threadId, boolean automatic) {
super(parameters);
this.messageId = messageId;
this.threadId = threadId;
this.automatic = automatic;
}
@Override
public @Nullable byte[] serialize() {
return new JsonJobData.Builder().putLong(KEY_MESSAGE_ID, messageId)
.putLong(KEY_THREAD_ID, threadId)
.putBoolean(KEY_AUTOMATIC, automatic)
.serialize();
}
@Override
public @NonNull String getFactoryKey() {
return KEY;
}
@Override
public void onAdded() {
if (automatic && KeyCachingService.isLocked(context)) {
SignalDatabase.messages().markIncomingNotificationReceived(threadId);
ApplicationDependencies.getMessageNotifier().updateNotification(context);
}
}
@Override
public void onRun() {
if (SignalStore.account().getE164() == null) {
throw new NotReadyException();
}
MessageTable database = SignalDatabase.messages();
Optional<MessageTable.MmsNotificationInfo> notification = database.getNotification(messageId);
if (!notification.isPresent()) {
Log.w(TAG, "No notification for ID: " + messageId);
return;
}
try {
if (notification.get().getContentLocation() == null) {
throw new MmsException("Notification content location was null.");
}
if (!SignalStore.account().isRegistered()) {
throw new MmsException("Not registered");
}
database.markDownloadState(messageId, MessageTable.MmsStatus.DOWNLOAD_CONNECTING);
String contentLocation = notification.get().getContentLocation();
byte[] transactionId = new byte[0];
try {
if (notification.get().getTransactionId() != null) {
transactionId = notification.get().getTransactionId().getBytes(CharacterSets.MIMENAME_ISO_8859_1);
} else {
Log.w(TAG, "No transaction ID!");
}
} catch (UnsupportedEncodingException e) {
Log.w(TAG, e);
}
Log.i(TAG, "Downloading mms at " + Uri.parse(contentLocation).getHost() + ", subscription ID: " + notification.get().getSubscriptionId());
RetrieveConf retrieveConf = new CompatMmsConnection(context).retrieve(contentLocation, transactionId, notification.get().getSubscriptionId());
if (retrieveConf == null) {
throw new MmsException("RetrieveConf was null");
}
storeRetrievedMms(contentLocation, messageId, threadId, retrieveConf, notification.get().getSubscriptionId(), notification.get().getFrom());
} catch (ApnUnavailableException e) {
Log.w(TAG, e);
handleDownloadError(messageId, threadId, MessageTable.MmsStatus.DOWNLOAD_APN_UNAVAILABLE,
automatic);
} catch (MmsException e) {
Log.w(TAG, e);
handleDownloadError(messageId, threadId,
MessageTable.MmsStatus.DOWNLOAD_HARD_FAILURE,
automatic);
} catch (MmsRadioException | IOException e) {
Log.w(TAG, e);
handleDownloadError(messageId, threadId,
MessageTable.MmsStatus.DOWNLOAD_SOFT_FAILURE,
automatic);
}
}
@Override
public void onFailure() {
MessageTable database = SignalDatabase.messages();
database.markDownloadState(messageId, MessageTable.MmsStatus.DOWNLOAD_SOFT_FAILURE);
if (automatic) {
database.markIncomingNotificationReceived(threadId);
ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(threadId));
}
}
@Override
public boolean onShouldRetry(@NonNull Exception exception) {
return false;
}
private void storeRetrievedMms(String contentLocation,
long messageId, long threadId, RetrieveConf retrieved,
int subscriptionId, @Nullable RecipientId notificationFrom)
throws MmsException
{
MessageTable database = SignalDatabase.messages();
Optional<GroupId> group = Optional.empty();
Set<RecipientId> members = new HashSet<>();
String body = null;
List<Attachment> attachments = new LinkedList<>();
List<Contact> sharedContacts = new LinkedList<>();
RecipientId from = null;
if (retrieved.getFrom() != null) {
from = Recipient.external(context, Util.toIsoString(retrieved.getFrom().getTextString())).getId();
} else if (notificationFrom != null) {
from = notificationFrom;
}
if (retrieved.getTo() != null) {
for (EncodedStringValue toValue : retrieved.getTo()) {
members.add(Recipient.external(context, Util.toIsoString(toValue.getTextString())).getId());
}
}
if (retrieved.getCc() != null) {
for (EncodedStringValue ccValue : retrieved.getCc()) {
members.add(Recipient.external(context, Util.toIsoString(ccValue.getTextString())).getId());
}
}
if (from != null) {
members.add(from);
}
members.add(Recipient.self().getId());
if (retrieved.getBody() != null) {
body = PartParser.getMessageText(retrieved.getBody());
PduBody media = PartParser.getSupportedMediaParts(retrieved.getBody());
for (int i=0;i<media.getPartsNum();i++) {
PduPart part = media.getPart(i);
if (part.getData() != null) {
if (Util.toIsoString(part.getContentType()).toLowerCase().equals(MediaUtil.VCARD)){
sharedContacts.addAll(VCardUtil.parseContacts(new String(part.getData())));
} else {
Uri uri = BlobProvider.getInstance().forData(part.getData()).createForSingleUseInMemory();
String name = null;
if (part.getName() != null) name = Util.toIsoString(part.getName());
attachments.add(new UriAttachment(uri, Util.toIsoString(part.getContentType()),
AttachmentTable.TRANSFER_PROGRESS_DONE,
part.getData().length, name, false, false, false, false, null, null, null, null, null));
}
}
}
}
if (members.size() > 2) {
Set<RecipientId> recipients = new HashSet<>(members);
group = Optional.of(SignalDatabase.groups().getOrCreateMmsGroupForMembers(recipients));
}
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, TimeUnit.SECONDS.toMillis(retrieved.getDate()), -1, System.currentTimeMillis(), attachments, subscriptionId, 0, false, false, false, Optional.of(sharedContacts), false, false);
Optional<InsertResult> insertResult = database.insertMessageInbox(message, contentLocation, threadId);
if (insertResult.isPresent()) {
database.deleteMessage(messageId);
ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.get().getThreadId()));
}
}
private void handleDownloadError(long messageId, long threadId, int downloadStatus, boolean automatic)
{
MessageTable db = SignalDatabase.messages();
db.markDownloadState(messageId, downloadStatus);
if (automatic) {
db.markIncomingNotificationReceived(threadId);
ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(threadId));
}
}
public static final class Factory implements Job.Factory<MmsDownloadJob> {
@Override
public @NonNull MmsDownloadJob create(@NonNull Parameters parameters, @Nullable byte[] serializedData) {
JsonJobData data = JsonJobData.deserialize(serializedData);
return new MmsDownloadJob(parameters,
data.getLong(KEY_MESSAGE_ID),
data.getLong(KEY_THREAD_ID),
data.getBoolean(KEY_AUTOMATIC));
}
}
private static class NotReadyException extends RuntimeException {
}
}

View File

@@ -1,140 +0,0 @@
package org.thoughtcrime.securesms.jobs;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.mms.pdu_alt.GenericPdu;
import com.google.android.mms.pdu_alt.NotificationInd;
import com.google.android.mms.pdu_alt.PduHeaders;
import com.google.android.mms.pdu_alt.PduParser;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.util.Pair;
import org.thoughtcrime.securesms.database.MessageTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.signal.core.util.Base64;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
public class MmsReceiveJob extends BaseJob {
public static final String KEY = "MmsReceiveJob";
private static final String TAG = Log.tag(MmsReceiveJob.class);
private static final String KEY_DATA = "data";
private static final String KEY_SUBSCRIPTION_ID = "subscription_id";
private byte[] data;
private int subscriptionId;
public MmsReceiveJob(byte[] data, int subscriptionId) {
this(new Job.Parameters.Builder().setMaxAttempts(25).build(), data, subscriptionId);
}
private MmsReceiveJob(@NonNull Job.Parameters parameters, byte[] data, int subscriptionId) {
super(parameters);
this.data = data;
this.subscriptionId = subscriptionId;
}
@Override
public @Nullable byte[] serialize() {
return new JsonJobData.Builder().putString(KEY_DATA, Base64.encodeWithPadding(data))
.putInt(KEY_SUBSCRIPTION_ID, subscriptionId)
.serialize();
}
@Override
public @NonNull String getFactoryKey() {
return KEY;
}
@Override
public void onRun() {
if (data == null) {
Log.w(TAG, "Received NULL pdu, ignoring...");
return;
}
PduParser parser = new PduParser(data);
GenericPdu pdu = null;
try {
pdu = parser.parse();
} catch (RuntimeException e) {
Log.w(TAG, e);
}
if (isNotification(pdu) && isBlocked(pdu)) {
Log.w(TAG, "Received an MMS from a blocked user. Ignoring.");
} else if (isNotification(pdu) && isSelf(pdu)) {
Log.w(TAG, "Received an MMS from ourselves! Ignoring.");
} else if (isNotification(pdu)) {
MessageTable database = SignalDatabase.messages();
Pair<Long, Long> messageAndThreadId = database.insertMessageInbox((NotificationInd)pdu, subscriptionId);
if (messageAndThreadId.first() > 0) {
Log.i(TAG, "Inserted received MMS notification...");
ApplicationDependencies.getJobManager().add(new MmsDownloadJob(messageAndThreadId.first(),
messageAndThreadId.second(),
true));
} else {
Log.w(TAG, "Did not insert MMS because it was a duplicate!");
}
} else {
Log.w(TAG, "Unable to process MMS.");
}
}
@Override
public void onFailure() {
// TODO
}
@Override
public boolean onShouldRetry(@NonNull Exception exception) {
return false;
}
private boolean isBlocked(GenericPdu pdu) {
if (pdu.getFrom() != null && pdu.getFrom().getTextString() != null) {
Recipient recipients = Recipient.external(context, Util.toIsoString(pdu.getFrom().getTextString()));
return recipients.isBlocked();
}
return false;
}
private boolean isSelf(GenericPdu pdu) {
if (pdu.getFrom() != null && pdu.getFrom().getTextString() != null) {
Recipient recipients = Recipient.external(context, Util.toIsoString(pdu.getFrom().getTextString()));
return recipients.isSelf();
}
return false;
}
private boolean isNotification(GenericPdu pdu) {
return pdu != null && pdu.getMessageType() == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
}
public static final class Factory implements Job.Factory<MmsReceiveJob> {
@Override
public @NonNull MmsReceiveJob create(@NonNull Parameters parameters, @Nullable byte[] serializedData) {
try {
JsonJobData data = JsonJobData.deserialize(serializedData);
return new MmsReceiveJob(parameters, Base64.decode(data.getString(KEY_DATA)), data.getInt(KEY_SUBSCRIPTION_ID));
} catch (IOException e) {
throw new AssertionError(e);
}
}
}
}

View File

@@ -1,243 +0,0 @@
package org.thoughtcrime.securesms.jobs;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsMessage;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.app.Person;
import com.google.android.gms.auth.api.phone.SmsRetriever;
import com.google.android.gms.common.api.Status;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.MessageTable;
import org.thoughtcrime.securesms.database.MessageTable.InsertResult;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.notifications.NotificationIds;
import org.thoughtcrime.securesms.notifications.v2.ConversationId;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.service.VerificationCodeParser;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.signal.core.util.Base64;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
public class SmsReceiveJob extends BaseJob {
public static final String KEY = "SmsReceiveJob";
private static final String TAG = Log.tag(SmsReceiveJob.class);
private static final String KEY_PDUS = "pdus";
private static final String KEY_SUBSCRIPTION_ID = "subscription_id";
private @Nullable Object[] pdus;
private int subscriptionId;
public SmsReceiveJob(@Nullable Object[] pdus, int subscriptionId) {
this(new Job.Parameters.Builder()
.addConstraint(SqlCipherMigrationConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
.build(),
pdus,
subscriptionId);
}
private SmsReceiveJob(@NonNull Job.Parameters parameters, @Nullable Object[] pdus, int subscriptionId) {
super(parameters);
this.pdus = pdus;
this.subscriptionId = subscriptionId;
}
@Override
public @Nullable byte[] serialize() {
String[] encoded = new String[pdus.length];
for (int i = 0; i < pdus.length; i++) {
encoded[i] = Base64.encodeWithPadding((byte[]) pdus[i]);
}
return new JsonJobData.Builder().putStringArray(KEY_PDUS, encoded)
.putInt(KEY_SUBSCRIPTION_ID, subscriptionId)
.serialize();
}
@Override
public @NonNull String getFactoryKey() {
return KEY;
}
@Override
public void onRun() throws MigrationPendingException, RetryLaterException {
Optional<IncomingTextMessage> message = assembleMessageFragments(pdus, subscriptionId);
if (SignalStore.account().getE164() == null) {
Log.i(TAG, "Received an SMS before we're registered...");
if (message.isPresent()) {
Optional<String> token = VerificationCodeParser.parse(message.get().getMessageBody());
if (token.isPresent()) {
Log.i(TAG, "Received something that looks like a registration SMS. Posting a notification and broadcast.");
NotificationManager manager = ServiceUtil.getNotificationManager(context);
Notification notification = buildPreRegistrationNotification(context, message.get());
manager.notify(NotificationIds.PRE_REGISTRATION_SMS, notification);
Intent smsRetrieverIntent = buildSmsRetrieverIntent(message.get());
context.sendBroadcast(smsRetrieverIntent);
return;
} else {
Log.w(TAG, "Received an SMS before registration is complete. We'll try again later.");
throw new RetryLaterException();
}
} else {
Log.w(TAG, "Received an SMS before registration is complete, but couldn't assemble the message anyway. Ignoring.");
return;
}
}
if (message.isPresent() && SignalStore.account().getE164() != null && message.get().getAuthorId().equals(Recipient.self().getId())) {
Log.w(TAG, "Received an SMS from ourselves! Ignoring.");
} else if (message.isPresent() && !isBlocked(message.get())) {
Optional<InsertResult> insertResult = storeMessage(message.get());
if (insertResult.isPresent()) {
ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.get().getThreadId()));
}
} else if (message.isPresent()) {
Log.w(TAG, "Received an SMS from a blocked user. Ignoring.");
} else {
Log.w(TAG, "Failed to assemble message fragments!");
}
}
@Override
public void onFailure() {
}
@Override
public boolean onShouldRetry(@NonNull Exception exception) {
return exception instanceof MigrationPendingException ||
exception instanceof RetryLaterException;
}
private boolean isBlocked(IncomingTextMessage message) {
if (message.getAuthorId() != null) {
Recipient recipient = Recipient.resolved(message.getAuthorId());
return recipient.isBlocked();
}
return false;
}
private Optional<InsertResult> storeMessage(IncomingTextMessage message) throws MigrationPendingException {
MessageTable database = SignalDatabase.messages();
database.ensureMigration();
if (TextSecurePreferences.getNeedsSqlCipherMigration(context)) {
throw new MigrationPendingException();
}
if (message.isSecureMessage()) {
IncomingTextMessage placeholder = new IncomingTextMessage(message, "");
Optional<InsertResult> insertResult = database.insertMessageInbox(placeholder);
database.markAsLegacyVersion(insertResult.get().getMessageId());
return insertResult;
} else {
return database.insertMessageInbox(message);
}
}
private Optional<IncomingTextMessage> assembleMessageFragments(@Nullable Object[] pdus, int subscriptionId) {
if (pdus == null) {
return Optional.empty();
}
List<IncomingTextMessage> messages = new LinkedList<>();
for (Object pdu : pdus) {
SmsMessage message = SmsMessage.createFromPdu((byte[])pdu);
Recipient recipient = Recipient.external(context, message.getDisplayOriginatingAddress());
messages.add(new IncomingTextMessage(recipient.getId(), message, subscriptionId));
}
if (messages.isEmpty()) {
return Optional.empty();
}
return Optional.of(new IncomingTextMessage(messages));
}
private static Notification buildPreRegistrationNotification(@NonNull Context context, @NonNull IncomingTextMessage message) {
Recipient sender = Recipient.resolved(message.getAuthorId());
return new NotificationCompat.Builder(context, NotificationChannels.getInstance().getMessagesChannel())
.setStyle(new NotificationCompat.MessagingStyle(new Person.Builder()
.setName(sender.getE164().orElse(""))
.build())
.addMessage(new NotificationCompat.MessagingStyle.Message(message.getMessageBody(),
message.getSentTimestampMillis(),
(Person) null)))
.setSmallIcon(R.drawable.ic_notification)
.build();
}
/**
* @return An intent that is identical to the one the {@link SmsRetriever} API uses, so that
* we can auto-populate the SMS code on capable devices.
*/
private static Intent buildSmsRetrieverIntent(@NonNull IncomingTextMessage message) {
Intent intent = new Intent(SmsRetriever.SMS_RETRIEVED_ACTION);
intent.putExtra(SmsRetriever.EXTRA_STATUS, Status.RESULT_SUCCESS);
intent.putExtra(SmsRetriever.EXTRA_SMS_MESSAGE, message.getMessageBody());
return intent;
}
public static final class Factory implements Job.Factory<SmsReceiveJob> {
@Override
public @NonNull SmsReceiveJob create(@NonNull Parameters parameters, @Nullable byte[] serializedData) {
JsonJobData data = JsonJobData.deserialize(serializedData);
try {
int subscriptionId = data.getInt(KEY_SUBSCRIPTION_ID);
String[] encoded = data.getStringArray(KEY_PDUS);
Object[] pdus = new Object[encoded.length];
for (int i = 0; i < encoded.length; i++) {
pdus[i] = Base64.decode(encoded[i]);
}
return new SmsReceiveJob(parameters, pdus, subscriptionId);
} catch (IOException e) {
throw new AssertionError(e);
}
}
}
private class MigrationPendingException extends Exception {
}
}

View File

@@ -1,61 +0,0 @@
/**
* Copyright (C) 2011 Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.MmsReceiveJob;
import org.thoughtcrime.securesms.util.Util;
public class MmsListener extends BroadcastReceiver {
private static final String TAG = Log.tag(MmsListener.class);
private boolean isRelevant(Context context, Intent intent) {
if (Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION.equals(intent.getAction()) && Util.isDefaultSmsProvider(context)) {
return false;
}
return false;
}
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Got MMS broadcast..." + intent.getAction());
if ((Telephony.Sms.Intents.WAP_PUSH_DELIVER_ACTION.equals(intent.getAction()) &&
Util.isDefaultSmsProvider(context)) ||
(Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION.equals(intent.getAction()) &&
isRelevant(context, intent)))
{
Log.i(TAG, "Relevant!");
int subscriptionId = intent.getExtras().getInt("subscription", -1);
ApplicationDependencies.getJobManager().add(new MmsReceiveJob(intent.getByteArrayExtra("data"), subscriptionId));
abortBroadcast();
}
}
}

View File

@@ -1,112 +0,0 @@
/**
* Copyright (C) 2011 Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Telephony;
import android.telephony.SmsMessage;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.SmsReceiveJob;
import org.thoughtcrime.securesms.util.Util;
public class SmsListener extends BroadcastReceiver {
private static final String TAG = Log.tag(SmsListener.class);
private static final String SMS_RECEIVED_ACTION = Telephony.Sms.Intents.SMS_RECEIVED_ACTION;
private static final String SMS_DELIVERED_ACTION = Telephony.Sms.Intents.SMS_DELIVER_ACTION;
private boolean isExemption(SmsMessage message, String messageBody) {
// ignore CLASS0 ("flash") messages
if (message.getMessageClass() == SmsMessage.MessageClass.CLASS_0)
return true;
// ignore OTP messages from Sparebank1 (Norwegian bank)
if (messageBody.startsWith("Sparebank1://otp?")) {
return true;
}
return
message.getOriginatingAddress().length() < 7 &&
(messageBody.toUpperCase().startsWith("//ANDROID:") || // Sprint Visual Voicemail
messageBody.startsWith("//BREW:")); //BREW stands for "Binary Runtime Environment for Wireless"
}
private SmsMessage getSmsMessageFromIntent(Intent intent) {
Bundle bundle = intent.getExtras();
Object[] pdus = (Object[])bundle.get("pdus");
if (pdus == null || pdus.length == 0)
return null;
return SmsMessage.createFromPdu((byte[])pdus[0]);
}
private String getSmsMessageBodyFromIntent(Intent intent) {
Bundle bundle = intent.getExtras();
Object[] pdus = (Object[])bundle.get("pdus");
StringBuilder bodyBuilder = new StringBuilder();
if (pdus == null)
return null;
for (Object pdu : pdus)
bodyBuilder.append(SmsMessage.createFromPdu((byte[])pdu).getDisplayMessageBody());
return bodyBuilder.toString();
}
private boolean isRelevant(Context context, Intent intent) {
SmsMessage message = getSmsMessageFromIntent(intent);
String messageBody = getSmsMessageBodyFromIntent(intent);
if (message == null && messageBody == null)
return false;
if (isExemption(message, messageBody))
return false;
if (SMS_RECEIVED_ACTION.equals(intent.getAction()) && Util.isDefaultSmsProvider(context)) {
return false;
}
return false;
}
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Got SMS broadcast...");
if ((intent.getAction().equals(SMS_DELIVERED_ACTION)) ||
(intent.getAction().equals(SMS_RECEIVED_ACTION)) && isRelevant(context, intent))
{
Log.i(TAG, "Constructing SmsReceiveJob...");
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
int subscriptionId = intent.getExtras().getInt("subscription", -1);
ApplicationDependencies.getJobManager().add(new SmsReceiveJob(pdus, subscriptionId));
abortBroadcast();
}
}
}