mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 21:15:48 +00:00
Remove sms/mms receive code.
Simplifying incoming message insert. Removing this dead path as part of it.
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user