package org.thoughtcrime.SMP.jobs; import android.content.Context; import android.telephony.SmsMessage; import android.util.Log; import android.util.Pair; import org.thoughtcrime.SMP.ApplicationContext; import org.thoughtcrime.SMP.crypto.MasterSecret; import org.thoughtcrime.SMP.crypto.MasterSecretUtil; import org.thoughtcrime.SMP.database.DatabaseFactory; import org.thoughtcrime.SMP.database.EncryptingSmsDatabase; import org.thoughtcrime.SMP.notifications.MessageNotifier; import org.thoughtcrime.SMP.protocol.WirePrefix; import org.thoughtcrime.SMP.recipients.RecipientFactory; import org.thoughtcrime.SMP.recipients.Recipients; import org.thoughtcrime.SMP.service.KeyCachingService; import org.thoughtcrime.SMP.sms.IncomingEncryptedMessage; import org.thoughtcrime.SMP.sms.IncomingTextMessage; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.libaxolotl.util.guava.Optional; import java.util.LinkedList; import java.util.List; public class SmsReceiveJob extends ContextJob { private static final String TAG = SmsReceiveJob.class.getSimpleName(); private final Object[] pdus; public SmsReceiveJob(Context context, Object[] pdus) { super(context, JobParameters.newBuilder() .withPersistence() .withWakeLock(true) .create()); this.pdus = pdus; } @Override public void onAdded() {} @Override public void onRun() { Optional<IncomingTextMessage> message = assembleMessageFragments(pdus); if (message.isPresent() && !isBlocked(message.get())) { Pair<Long, Long> messageAndThreadId = storeMessage(message.get()); MessageNotifier.updateNotification(context, KeyCachingService.getMasterSecret(context), messageAndThreadId.second); } else if (message.isPresent()) { Log.w(TAG, "*** Received blocked SMS, ignoring..."); } } @Override public void onCanceled() { } @Override public boolean onShouldRetry(Exception exception) { return false; } private boolean isBlocked(IncomingTextMessage message) { if (message.getSender() != null) { Recipients recipients = RecipientFactory.getRecipientsFromString(context, message.getSender(), false); return recipients.isBlocked(); } return false; } private Pair<Long, Long> storeMessage(IncomingTextMessage message) { EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); MasterSecret masterSecret = KeyCachingService.getMasterSecret(context); Pair<Long, Long> messageAndThreadId; if (message.isSecureMessage()) { messageAndThreadId = database.insertMessageInbox((MasterSecret)null, message); database.markAsLegacyVersion(messageAndThreadId.first); } else if (masterSecret == null) { messageAndThreadId = database.insertMessageInbox(MasterSecretUtil.getAsymmetricMasterSecret(context, null), message); ApplicationContext.getInstance(context) .getJobManager() .add(new SmsDecryptJob(context, messageAndThreadId.first)); } else { messageAndThreadId = database.insertMessageInbox(masterSecret, message); } return messageAndThreadId; } private Optional<IncomingTextMessage> assembleMessageFragments(Object[] pdus) { List<IncomingTextMessage> messages = new LinkedList<>(); for (Object pdu : pdus) { messages.add(new IncomingTextMessage(SmsMessage.createFromPdu((byte[])pdu))); } if (messages.isEmpty()) { return Optional.absent(); } IncomingTextMessage message = new IncomingTextMessage(messages); if (WirePrefix.isEncryptedMessage(message.getMessageBody()) || WirePrefix.isKeyExchange(message.getMessageBody()) || WirePrefix.isPreKeyBundle(message.getMessageBody()) || WirePrefix.isEndSession(message.getMessageBody())) { return Optional.<IncomingTextMessage>of(new IncomingEncryptedMessage(message, message.getMessageBody())); } else { return Optional.of(message); } } }