2014-11-03 23:16:04 +00:00
|
|
|
package org.thoughtcrime.securesms.jobs;
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2012-09-30 18:46:45 +00:00
|
|
|
import android.content.Context;
|
2014-07-29 22:31:20 +00:00
|
|
|
import android.net.Uri;
|
2017-09-08 18:19:57 +00:00
|
|
|
import android.support.annotation.Nullable;
|
2012-09-30 18:46:45 +00:00
|
|
|
import android.util.Log;
|
2017-05-08 22:32:59 +00:00
|
|
|
|
|
|
|
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;
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2015-10-13 01:25:05 +00:00
|
|
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
|
|
|
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
2014-11-03 23:16:04 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
2015-07-07 00:36:49 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
2017-08-01 15:56:00 +00:00
|
|
|
import org.thoughtcrime.securesms.database.Address;
|
2016-02-06 00:10:33 +00:00
|
|
|
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
2011-12-20 18:20:44 +00:00
|
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
2017-01-22 21:52:36 +00:00
|
|
|
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
2011-12-20 18:20:44 +00:00
|
|
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
2014-11-03 23:16:04 +00:00
|
|
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
2013-09-16 07:55:01 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
2015-05-01 19:03:05 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
2013-07-19 00:42:45 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
2017-07-26 16:59:15 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.MmsException;
|
2013-07-17 02:52:02 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
2015-10-24 16:40:04 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.PartParser;
|
2013-04-26 18:23:43 +00:00
|
|
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
2015-10-13 01:25:05 +00:00
|
|
|
import org.thoughtcrime.securesms.providers.SingleUseBlobProvider;
|
2014-11-03 23:16:04 +00:00
|
|
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
2017-08-01 15:56:00 +00:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
2015-10-13 01:25:05 +00:00
|
|
|
import org.thoughtcrime.securesms.util.Util;
|
2014-11-03 23:16:04 +00:00
|
|
|
import org.whispersystems.jobqueue.JobParameters;
|
|
|
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
2016-03-23 17:34:41 +00:00
|
|
|
import org.whispersystems.libsignal.DuplicateMessageException;
|
|
|
|
import org.whispersystems.libsignal.InvalidMessageException;
|
|
|
|
import org.whispersystems.libsignal.LegacyMessageException;
|
|
|
|
import org.whispersystems.libsignal.NoSessionException;
|
|
|
|
import org.whispersystems.libsignal.util.guava.Optional;
|
2011-12-20 18:20:44 +00:00
|
|
|
|
2013-09-16 07:55:01 +00:00
|
|
|
import java.io.IOException;
|
2017-05-08 22:32:59 +00:00
|
|
|
import java.io.UnsupportedEncodingException;
|
2017-08-01 15:56:00 +00:00
|
|
|
import java.util.HashSet;
|
2015-10-13 01:25:05 +00:00
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.util.List;
|
2017-08-01 15:56:00 +00:00
|
|
|
import java.util.Set;
|
2015-03-18 21:25:27 +00:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2013-09-16 07:55:01 +00:00
|
|
|
|
2014-11-03 23:16:04 +00:00
|
|
|
public class MmsDownloadJob extends MasterSecretJob {
|
2012-09-30 18:46:45 +00:00
|
|
|
|
2014-11-03 23:16:04 +00:00
|
|
|
private static final String TAG = MmsDownloadJob.class.getSimpleName();
|
|
|
|
|
|
|
|
private final long messageId;
|
|
|
|
private final long threadId;
|
|
|
|
private final boolean automatic;
|
|
|
|
|
|
|
|
public MmsDownloadJob(Context context, long messageId, long threadId, boolean automatic) {
|
|
|
|
super(context, JobParameters.newBuilder()
|
|
|
|
.withPersistence()
|
|
|
|
.withRequirement(new MasterSecretRequirement(context))
|
|
|
|
.withRequirement(new NetworkRequirement(context))
|
2014-11-08 19:35:58 +00:00
|
|
|
.withGroupId("mms-operation")
|
2015-03-18 21:25:27 +00:00
|
|
|
.withWakeLock(true, 30, TimeUnit.SECONDS)
|
2014-11-03 23:16:04 +00:00
|
|
|
.create());
|
|
|
|
|
|
|
|
this.messageId = messageId;
|
|
|
|
this.threadId = threadId;
|
|
|
|
this.automatic = automatic;
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
2012-09-30 18:46:45 +00:00
|
|
|
|
2014-11-03 23:16:04 +00:00
|
|
|
@Override
|
|
|
|
public void onAdded() {
|
|
|
|
if (automatic && KeyCachingService.getMasterSecret(context) == null) {
|
|
|
|
DatabaseFactory.getMmsDatabase(context).markIncomingNotificationReceived(threadId);
|
|
|
|
MessageNotifier.updateNotification(context, null);
|
2013-02-21 02:10:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-03 23:16:04 +00:00
|
|
|
@Override
|
2014-12-29 22:01:02 +00:00
|
|
|
public void onRun(MasterSecret masterSecret) {
|
2017-05-08 22:32:59 +00:00
|
|
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
|
|
|
Optional<MmsDatabase.MmsNotificationInfo> notification = database.getNotification(messageId);
|
2013-09-16 07:55:01 +00:00
|
|
|
|
2014-11-03 23:16:04 +00:00
|
|
|
if (!notification.isPresent()) {
|
|
|
|
Log.w(TAG, "No notification for ID: " + messageId);
|
|
|
|
return;
|
2013-09-16 07:55:01 +00:00
|
|
|
}
|
|
|
|
|
2015-04-13 17:56:41 +00:00
|
|
|
try {
|
2017-05-08 22:32:59 +00:00
|
|
|
if (notification.get().getContentLocation() == null) {
|
2015-04-13 17:56:41 +00:00
|
|
|
throw new MmsException("Notification content location was null.");
|
|
|
|
}
|
2013-09-16 07:55:01 +00:00
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
if (!TextSecurePreferences.isPushRegistered(context)) {
|
|
|
|
throw new MmsException("Not registered");
|
|
|
|
}
|
|
|
|
|
2015-04-13 17:56:41 +00:00
|
|
|
database.markDownloadState(messageId, MmsDatabase.Status.DOWNLOAD_CONNECTING);
|
2012-09-30 18:46:45 +00:00
|
|
|
|
2017-05-08 22:32:59 +00:00
|
|
|
String contentLocation = notification.get().getContentLocation();
|
|
|
|
byte[] transactionId = new byte[0];
|
|
|
|
|
|
|
|
try {
|
2017-09-13 23:38:02 +00:00
|
|
|
if (notification.get().getTransactionId() != null) {
|
|
|
|
transactionId = notification.get().getTransactionId().getBytes(CharacterSets.MIMENAME_ISO_8859_1);
|
|
|
|
} else {
|
|
|
|
Log.w(TAG, "No transaction ID!");
|
|
|
|
}
|
2017-05-08 22:32:59 +00:00
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
}
|
2015-04-13 17:56:41 +00:00
|
|
|
|
2017-05-24 17:52:08 +00:00
|
|
|
Log.w(TAG, "Downloading mms at " + Uri.parse(contentLocation).getHost() + ", subscription ID: " + notification.get().getSubscriptionId());
|
2014-07-29 22:31:20 +00:00
|
|
|
|
2017-05-08 22:32:59 +00:00
|
|
|
RetrieveConf retrieveConf = new CompatMmsConnection(context).retrieve(contentLocation, transactionId, notification.get().getSubscriptionId());
|
2016-02-06 00:10:33 +00:00
|
|
|
|
2015-03-30 17:46:14 +00:00
|
|
|
if (retrieveConf == null) {
|
|
|
|
throw new MmsException("RetrieveConf was null");
|
|
|
|
}
|
2016-02-06 00:10:33 +00:00
|
|
|
|
2017-09-08 18:19:57 +00:00
|
|
|
storeRetrievedMms(masterSecret, contentLocation, messageId, threadId, retrieveConf, notification.get().getSubscriptionId(), notification.get().getFrom());
|
2013-09-16 07:55:01 +00:00
|
|
|
} catch (ApnUnavailableException e) {
|
2014-11-03 23:16:04 +00:00
|
|
|
Log.w(TAG, e);
|
2013-07-17 02:52:02 +00:00
|
|
|
handleDownloadError(masterSecret, messageId, threadId, MmsDatabase.Status.DOWNLOAD_APN_UNAVAILABLE,
|
2014-12-29 22:01:02 +00:00
|
|
|
automatic);
|
2011-12-20 18:20:44 +00:00
|
|
|
} catch (MmsException e) {
|
2014-11-03 23:16:04 +00:00
|
|
|
Log.w(TAG, e);
|
2013-07-17 02:52:02 +00:00
|
|
|
handleDownloadError(masterSecret, messageId, threadId,
|
|
|
|
MmsDatabase.Status.DOWNLOAD_HARD_FAILURE,
|
|
|
|
automatic);
|
2014-12-29 22:01:02 +00:00
|
|
|
} catch (MmsRadioException | IOException e) {
|
2014-11-03 23:16:04 +00:00
|
|
|
Log.w(TAG, e);
|
2013-07-17 02:52:02 +00:00
|
|
|
handleDownloadError(masterSecret, messageId, threadId,
|
|
|
|
MmsDatabase.Status.DOWNLOAD_SOFT_FAILURE,
|
|
|
|
automatic);
|
2014-11-03 23:16:04 +00:00
|
|
|
} catch (DuplicateMessageException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
database.markAsDecryptDuplicate(messageId, threadId);
|
|
|
|
} catch (LegacyMessageException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
database.markAsLegacyVersion(messageId, threadId);
|
|
|
|
} catch (NoSessionException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
database.markAsNoSession(messageId, threadId);
|
|
|
|
} catch (InvalidMessageException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
database.markAsDecryptFailed(messageId, threadId);
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
}
|
2012-09-30 18:46:45 +00:00
|
|
|
|
2014-11-03 23:16:04 +00:00
|
|
|
@Override
|
|
|
|
public void onCanceled() {
|
2014-11-08 19:35:58 +00:00
|
|
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
|
|
|
database.markDownloadState(messageId, MmsDatabase.Status.DOWNLOAD_SOFT_FAILURE);
|
|
|
|
|
|
|
|
if (automatic) {
|
|
|
|
database.markIncomingNotificationReceived(threadId);
|
|
|
|
MessageNotifier.updateNotification(context, null, threadId);
|
|
|
|
}
|
2014-11-03 23:16:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2014-11-12 05:11:57 +00:00
|
|
|
public boolean onShouldRetryThrowable(Exception exception) {
|
2014-11-03 23:16:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-07-17 02:52:02 +00:00
|
|
|
private void storeRetrievedMms(MasterSecret masterSecret, String contentLocation,
|
2016-02-06 00:10:33 +00:00
|
|
|
long messageId, long threadId, RetrieveConf retrieved,
|
2017-09-08 18:19:57 +00:00
|
|
|
int subscriptionId, @Nullable Address notificationFrom)
|
2014-11-03 23:16:04 +00:00
|
|
|
throws MmsException, NoSessionException, DuplicateMessageException, InvalidMessageException,
|
|
|
|
LegacyMessageException
|
2013-02-21 02:10:33 +00:00
|
|
|
{
|
2015-10-13 01:25:05 +00:00
|
|
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
|
|
|
SingleUseBlobProvider provider = SingleUseBlobProvider.getInstance();
|
2017-08-01 15:56:00 +00:00
|
|
|
Optional<Address> group = Optional.absent();
|
|
|
|
Set<Address> members = new HashSet<>();
|
2015-10-13 01:25:05 +00:00
|
|
|
String body = null;
|
|
|
|
List<Attachment> attachments = new LinkedList<>();
|
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
Address from;
|
|
|
|
|
2015-10-13 01:25:05 +00:00
|
|
|
if (retrieved.getFrom() != null) {
|
2017-08-01 15:56:00 +00:00
|
|
|
from = Address.fromExternal(context, Util.toIsoString(retrieved.getFrom().getTextString()));
|
2017-09-08 18:19:57 +00:00
|
|
|
} else if (notificationFrom != null) {
|
|
|
|
from = notificationFrom;
|
2017-08-01 15:56:00 +00:00
|
|
|
} else {
|
|
|
|
from = Address.UNKNOWN;
|
2015-10-13 01:25:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (retrieved.getTo() != null) {
|
|
|
|
for (EncodedStringValue toValue : retrieved.getTo()) {
|
2017-08-01 15:56:00 +00:00
|
|
|
members.add(Address.fromExternal(context, Util.toIsoString(toValue.getTextString())));
|
2015-10-13 01:25:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retrieved.getCc() != null) {
|
|
|
|
for (EncodedStringValue ccValue : retrieved.getCc()) {
|
2017-08-01 15:56:00 +00:00
|
|
|
members.add(Address.fromExternal(context, Util.toIsoString(ccValue.getTextString())));
|
2015-10-13 01:25:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 18:19:57 +00:00
|
|
|
members.add(from);
|
2017-08-01 15:56:00 +00:00
|
|
|
members.add(Address.fromExternal(context, TextSecurePreferences.getLocalNumber(context)));
|
|
|
|
|
2015-10-13 01:25:05 +00:00
|
|
|
if (retrieved.getBody() != null) {
|
2015-10-24 16:40:04 +00:00
|
|
|
body = PartParser.getMessageText(retrieved.getBody());
|
|
|
|
PduBody media = PartParser.getSupportedMediaParts(retrieved.getBody());
|
2015-10-13 01:25:05 +00:00
|
|
|
|
2015-10-24 16:40:04 +00:00
|
|
|
for (int i=0;i<media.getPartsNum();i++) {
|
|
|
|
PduPart part = media.getPart(i);
|
|
|
|
|
|
|
|
if (part.getData() != null) {
|
2017-03-28 19:05:30 +00:00
|
|
|
Uri uri = provider.createUri(part.getData());
|
|
|
|
String name = null;
|
|
|
|
|
|
|
|
if (part.getName() != null) name = Util.toIsoString(part.getName());
|
|
|
|
|
2015-10-13 01:25:05 +00:00
|
|
|
attachments.add(new UriAttachment(uri, Util.toIsoString(part.getContentType()),
|
|
|
|
AttachmentDatabase.TRANSFER_PROGRESS_DONE,
|
2017-05-12 05:46:35 +00:00
|
|
|
part.getData().length, name, false));
|
2015-10-13 01:25:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-10 18:13:53 +00:00
|
|
|
if (members.size() > 2) {
|
2017-08-01 15:56:00 +00:00
|
|
|
group = Optional.of(Address.fromSerialized(DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(new LinkedList<>(members), true)));
|
|
|
|
}
|
2015-10-13 01:25:05 +00:00
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false);
|
2017-01-22 21:52:36 +00:00
|
|
|
Optional<InsertResult> insertResult = database.insertMessageInbox(new MasterSecretUnion(masterSecret),
|
|
|
|
message, contentLocation, threadId);
|
2013-07-19 00:42:45 +00:00
|
|
|
|
2017-01-22 21:52:36 +00:00
|
|
|
if (insertResult.isPresent()) {
|
|
|
|
database.delete(messageId);
|
|
|
|
MessageNotifier.updateNotification(context, masterSecret, insertResult.get().getThreadId());
|
|
|
|
}
|
2013-02-21 02:10:33 +00:00
|
|
|
}
|
|
|
|
|
2013-07-17 02:52:02 +00:00
|
|
|
private void handleDownloadError(MasterSecret masterSecret, long messageId, long threadId,
|
2014-12-29 22:01:02 +00:00
|
|
|
int downloadStatus, boolean automatic)
|
2013-07-17 02:52:02 +00:00
|
|
|
{
|
2013-04-26 18:23:43 +00:00
|
|
|
MmsDatabase db = DatabaseFactory.getMmsDatabase(context);
|
2012-09-30 18:46:45 +00:00
|
|
|
|
2013-07-17 02:52:02 +00:00
|
|
|
db.markDownloadState(messageId, downloadStatus);
|
2013-02-21 02:10:33 +00:00
|
|
|
|
2013-07-17 02:52:02 +00:00
|
|
|
if (automatic) {
|
|
|
|
db.markIncomingNotificationReceived(threadId);
|
|
|
|
MessageNotifier.updateNotification(context, masterSecret, threadId);
|
2013-02-21 02:10:33 +00:00
|
|
|
}
|
2011-12-20 18:20:44 +00:00
|
|
|
}
|
|
|
|
}
|