2014-11-04 00:16:04 +01:00
|
|
|
package org.thoughtcrime.securesms.jobs;
|
2011-12-20 19:20:44 +01:00
|
|
|
|
2014-07-30 00:31:20 +02:00
|
|
|
import android.net.Uri;
|
2020-03-26 15:00:17 +01:00
|
|
|
|
2019-06-05 21:47:14 +02:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2018-08-09 16:15:43 +02:00
|
|
|
|
2017-05-09 00:32:59 +02: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 19:20:44 +01:00
|
|
|
|
2015-10-13 03:25:05 +02:00
|
|
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
|
|
|
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
2016-02-06 01:10:33 +01:00
|
|
|
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
2011-12-20 19:20:44 +01:00
|
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
2017-01-22 22:52:36 +01:00
|
|
|
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
2011-12-20 19:20:44 +01:00
|
|
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
2020-03-26 15:00:17 +01:00
|
|
|
import org.thoughtcrime.securesms.groups.GroupId;
|
2019-04-17 16:21:30 +02:00
|
|
|
import org.thoughtcrime.securesms.jobmanager.Data;
|
|
|
|
import org.thoughtcrime.securesms.jobmanager.Job;
|
|
|
|
import org.thoughtcrime.securesms.logging.Log;
|
2013-09-16 09:55:01 +02:00
|
|
|
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
2015-05-01 21:03:05 +02:00
|
|
|
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
2013-07-19 02:42:45 +02:00
|
|
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
2017-07-26 18:59:15 +02:00
|
|
|
import org.thoughtcrime.securesms.mms.MmsException;
|
2013-07-17 04:52:02 +02:00
|
|
|
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
2015-10-24 18:40:04 +02:00
|
|
|
import org.thoughtcrime.securesms.mms.PartParser;
|
2013-04-26 20:23:43 +02:00
|
|
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
2019-02-26 02:47:30 +01:00
|
|
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
2019-08-07 20:22:51 +02:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
2014-11-04 00:16:04 +01:00
|
|
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
2017-08-01 17:56:00 +02:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
2015-10-13 03:25:05 +02:00
|
|
|
import org.thoughtcrime.securesms.util.Util;
|
2016-03-23 18:34:41 +01:00
|
|
|
import org.whispersystems.libsignal.util.guava.Optional;
|
2011-12-20 19:20:44 +01:00
|
|
|
|
2013-09-16 09:55:01 +02:00
|
|
|
import java.io.IOException;
|
2017-05-09 00:32:59 +02:00
|
|
|
import java.io.UnsupportedEncodingException;
|
2019-08-07 20:22:51 +02:00
|
|
|
import java.util.ArrayList;
|
2017-08-01 17:56:00 +02:00
|
|
|
import java.util.HashSet;
|
2015-10-13 03:25:05 +02:00
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.util.List;
|
2017-08-01 17:56:00 +02:00
|
|
|
import java.util.Set;
|
2018-08-09 16:15:43 +02:00
|
|
|
|
2019-03-28 16:56:35 +01:00
|
|
|
public class MmsDownloadJob extends BaseJob {
|
2013-09-16 09:55:01 +02:00
|
|
|
|
2019-03-28 16:56:35 +01:00
|
|
|
public static final String KEY = "MmsDownloadJob";
|
2018-01-25 04:17:44 +01:00
|
|
|
|
2014-11-04 00:16:04 +01:00
|
|
|
private static final String TAG = MmsDownloadJob.class.getSimpleName();
|
|
|
|
|
2018-08-09 16:15:43 +02:00
|
|
|
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;
|
|
|
|
|
2019-03-28 16:56:35 +01:00
|
|
|
public MmsDownloadJob(long messageId, long threadId, boolean automatic) {
|
|
|
|
this(new Job.Parameters.Builder()
|
|
|
|
.setQueue("mms-operation")
|
|
|
|
.setMaxAttempts(25)
|
|
|
|
.build(),
|
|
|
|
messageId,
|
|
|
|
threadId,
|
|
|
|
automatic);
|
|
|
|
|
2018-08-09 16:15:43 +02:00
|
|
|
}
|
2014-11-04 00:16:04 +01:00
|
|
|
|
2019-03-28 16:56:35 +01:00
|
|
|
private MmsDownloadJob(@NonNull Job.Parameters parameters, long messageId, long threadId, boolean automatic) {
|
|
|
|
super(parameters);
|
2014-11-04 00:16:04 +01:00
|
|
|
|
|
|
|
this.messageId = messageId;
|
|
|
|
this.threadId = threadId;
|
|
|
|
this.automatic = automatic;
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|
2012-09-30 20:46:45 +02:00
|
|
|
|
2018-08-09 16:15:43 +02:00
|
|
|
@Override
|
2019-03-28 16:56:35 +01:00
|
|
|
public @NonNull Data serialize() {
|
|
|
|
return new Data.Builder().putLong(KEY_MESSAGE_ID, messageId)
|
|
|
|
.putLong(KEY_THREAD_ID, threadId)
|
|
|
|
.putBoolean(KEY_AUTOMATIC, automatic)
|
|
|
|
.build();
|
2018-08-09 16:15:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2019-03-28 16:56:35 +01:00
|
|
|
public @NonNull String getFactoryKey() {
|
|
|
|
return KEY;
|
2018-08-09 16:15:43 +02:00
|
|
|
}
|
|
|
|
|
2014-11-04 00:16:04 +01:00
|
|
|
@Override
|
|
|
|
public void onAdded() {
|
2018-10-10 17:50:35 +02:00
|
|
|
if (automatic && KeyCachingService.isLocked(context)) {
|
2014-11-04 00:16:04 +01:00
|
|
|
DatabaseFactory.getMmsDatabase(context).markIncomingNotificationReceived(threadId);
|
2018-01-25 04:17:44 +01:00
|
|
|
MessageNotifier.updateNotification(context);
|
2013-02-21 03:10:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-04 00:16:04 +01:00
|
|
|
@Override
|
2018-11-15 21:05:08 +01:00
|
|
|
public void onRun() {
|
2017-05-09 00:32:59 +02:00
|
|
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
|
|
|
Optional<MmsDatabase.MmsNotificationInfo> notification = database.getNotification(messageId);
|
2013-09-16 09:55:01 +02:00
|
|
|
|
2014-11-04 00:16:04 +01:00
|
|
|
if (!notification.isPresent()) {
|
|
|
|
Log.w(TAG, "No notification for ID: " + messageId);
|
|
|
|
return;
|
2013-09-16 09:55:01 +02:00
|
|
|
}
|
|
|
|
|
2015-04-13 19:56:41 +02:00
|
|
|
try {
|
2017-05-09 00:32:59 +02:00
|
|
|
if (notification.get().getContentLocation() == null) {
|
2015-04-13 19:56:41 +02:00
|
|
|
throw new MmsException("Notification content location was null.");
|
|
|
|
}
|
2013-09-16 09:55:01 +02:00
|
|
|
|
2017-08-01 17:56:00 +02:00
|
|
|
if (!TextSecurePreferences.isPushRegistered(context)) {
|
|
|
|
throw new MmsException("Not registered");
|
|
|
|
}
|
|
|
|
|
2015-04-13 19:56:41 +02:00
|
|
|
database.markDownloadState(messageId, MmsDatabase.Status.DOWNLOAD_CONNECTING);
|
2012-09-30 20:46:45 +02:00
|
|
|
|
2017-05-09 00:32:59 +02:00
|
|
|
String contentLocation = notification.get().getContentLocation();
|
|
|
|
byte[] transactionId = new byte[0];
|
|
|
|
|
|
|
|
try {
|
2017-09-14 01:38:02 +02: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-09 00:32:59 +02:00
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
}
|
2015-04-13 19:56:41 +02:00
|
|
|
|
2018-08-02 15:25:33 +02:00
|
|
|
Log.i(TAG, "Downloading mms at " + Uri.parse(contentLocation).getHost() + ", subscription ID: " + notification.get().getSubscriptionId());
|
2014-07-30 00:31:20 +02:00
|
|
|
|
2017-05-09 00:32:59 +02:00
|
|
|
RetrieveConf retrieveConf = new CompatMmsConnection(context).retrieve(contentLocation, transactionId, notification.get().getSubscriptionId());
|
2016-02-06 01:10:33 +01:00
|
|
|
|
2015-03-30 19:46:14 +02:00
|
|
|
if (retrieveConf == null) {
|
|
|
|
throw new MmsException("RetrieveConf was null");
|
|
|
|
}
|
2016-02-06 01:10:33 +01:00
|
|
|
|
2018-01-25 04:17:44 +01:00
|
|
|
storeRetrievedMms(contentLocation, messageId, threadId, retrieveConf, notification.get().getSubscriptionId(), notification.get().getFrom());
|
2013-09-16 09:55:01 +02:00
|
|
|
} catch (ApnUnavailableException e) {
|
2014-11-04 00:16:04 +01:00
|
|
|
Log.w(TAG, e);
|
2018-01-25 04:17:44 +01:00
|
|
|
handleDownloadError(messageId, threadId, MmsDatabase.Status.DOWNLOAD_APN_UNAVAILABLE,
|
2014-12-29 23:01:02 +01:00
|
|
|
automatic);
|
2011-12-20 19:20:44 +01:00
|
|
|
} catch (MmsException e) {
|
2014-11-04 00:16:04 +01:00
|
|
|
Log.w(TAG, e);
|
2018-01-25 04:17:44 +01:00
|
|
|
handleDownloadError(messageId, threadId,
|
2013-07-17 04:52:02 +02:00
|
|
|
MmsDatabase.Status.DOWNLOAD_HARD_FAILURE,
|
|
|
|
automatic);
|
2014-12-29 23:01:02 +01:00
|
|
|
} catch (MmsRadioException | IOException e) {
|
2014-11-04 00:16:04 +01:00
|
|
|
Log.w(TAG, e);
|
2018-01-25 04:17:44 +01:00
|
|
|
handleDownloadError(messageId, threadId,
|
2013-07-17 04:52:02 +02:00
|
|
|
MmsDatabase.Status.DOWNLOAD_SOFT_FAILURE,
|
|
|
|
automatic);
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|
|
|
|
}
|
2012-09-30 20:46:45 +02:00
|
|
|
|
2014-11-04 00:16:04 +01:00
|
|
|
@Override
|
2020-01-03 20:10:16 +01:00
|
|
|
public void onFailure() {
|
2014-11-08 20:35:58 +01:00
|
|
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
|
|
|
database.markDownloadState(messageId, MmsDatabase.Status.DOWNLOAD_SOFT_FAILURE);
|
|
|
|
|
|
|
|
if (automatic) {
|
|
|
|
database.markIncomingNotificationReceived(threadId);
|
2018-01-25 04:17:44 +01:00
|
|
|
MessageNotifier.updateNotification(context, threadId);
|
2014-11-08 20:35:58 +01:00
|
|
|
}
|
2014-11-04 00:16:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2019-05-22 18:51:56 +02:00
|
|
|
public boolean onShouldRetry(@NonNull Exception exception) {
|
2014-11-04 00:16:04 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-01-25 04:17:44 +01:00
|
|
|
private void storeRetrievedMms(String contentLocation,
|
2016-02-06 01:10:33 +01:00
|
|
|
long messageId, long threadId, RetrieveConf retrieved,
|
2019-08-07 20:22:51 +02:00
|
|
|
int subscriptionId, @Nullable RecipientId notificationFrom)
|
|
|
|
throws MmsException
|
2013-02-21 03:10:33 +01:00
|
|
|
{
|
2020-03-26 15:00:17 +01:00
|
|
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
|
|
|
Optional<GroupId> group = Optional.absent();
|
|
|
|
Set<RecipientId> members = new HashSet<>();
|
|
|
|
String body = null;
|
|
|
|
List<Attachment> attachments = new LinkedList<>();
|
2015-10-13 03:25:05 +02:00
|
|
|
|
2019-10-08 22:33:13 +02:00
|
|
|
RecipientId from = null;
|
2017-08-01 17:56:00 +02:00
|
|
|
|
2015-10-13 03:25:05 +02:00
|
|
|
if (retrieved.getFrom() != null) {
|
2019-08-07 20:22:51 +02:00
|
|
|
from = Recipient.external(context, Util.toIsoString(retrieved.getFrom().getTextString())).getId();
|
2017-09-08 20:19:57 +02:00
|
|
|
} else if (notificationFrom != null) {
|
|
|
|
from = notificationFrom;
|
2015-10-13 03:25:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (retrieved.getTo() != null) {
|
|
|
|
for (EncodedStringValue toValue : retrieved.getTo()) {
|
2019-08-07 20:22:51 +02:00
|
|
|
members.add(Recipient.external(context, Util.toIsoString(toValue.getTextString())).getId());
|
2015-10-13 03:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retrieved.getCc() != null) {
|
|
|
|
for (EncodedStringValue ccValue : retrieved.getCc()) {
|
2019-08-07 20:22:51 +02:00
|
|
|
members.add(Recipient.external(context, Util.toIsoString(ccValue.getTextString())).getId());
|
2015-10-13 03:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-08 22:33:13 +02:00
|
|
|
if (from != null) {
|
|
|
|
members.add(from);
|
|
|
|
}
|
2019-08-07 20:22:51 +02:00
|
|
|
members.add(Recipient.self().getId());
|
2017-08-01 17:56:00 +02:00
|
|
|
|
2015-10-13 03:25:05 +02:00
|
|
|
if (retrieved.getBody() != null) {
|
2015-10-24 18:40:04 +02:00
|
|
|
body = PartParser.getMessageText(retrieved.getBody());
|
|
|
|
PduBody media = PartParser.getSupportedMediaParts(retrieved.getBody());
|
2015-10-13 03:25:05 +02:00
|
|
|
|
2015-10-24 18:40:04 +02:00
|
|
|
for (int i=0;i<media.getPartsNum();i++) {
|
|
|
|
PduPart part = media.getPart(i);
|
|
|
|
|
|
|
|
if (part.getData() != null) {
|
2019-02-26 02:47:30 +01:00
|
|
|
Uri uri = BlobProvider.getInstance().forData(part.getData()).createForSingleUseInMemory();
|
2017-03-28 21:05:30 +02:00
|
|
|
String name = null;
|
|
|
|
|
|
|
|
if (part.getName() != null) name = Util.toIsoString(part.getName());
|
|
|
|
|
2015-10-13 03:25:05 +02:00
|
|
|
attachments.add(new UriAttachment(uri, Util.toIsoString(part.getContentType()),
|
|
|
|
AttachmentDatabase.TRANSFER_PROGRESS_DONE,
|
2019-10-21 18:11:12 +02:00
|
|
|
part.getData().length, name, false, false, null, null, null, null));
|
2015-10-13 03:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-10 20:13:53 +02:00
|
|
|
if (members.size() > 2) {
|
2019-08-07 20:22:51 +02:00
|
|
|
List<RecipientId> recipients = new ArrayList<>(members);
|
2020-03-27 19:55:44 +01:00
|
|
|
group = Optional.of(DatabaseFactory.getGroupDatabase(context).getOrCreateMmsGroupForMembers(recipients));
|
2017-08-01 17:56:00 +02:00
|
|
|
}
|
2015-10-13 03:25:05 +02:00
|
|
|
|
2019-08-01 01:33:56 +02:00
|
|
|
IncomingMediaMessage message = new IncomingMediaMessage(from, group, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false, false, false);
|
2018-01-25 04:17:44 +01:00
|
|
|
Optional<InsertResult> insertResult = database.insertMessageInbox(message, contentLocation, threadId);
|
2013-07-19 02:42:45 +02:00
|
|
|
|
2017-01-22 22:52:36 +01:00
|
|
|
if (insertResult.isPresent()) {
|
|
|
|
database.delete(messageId);
|
2018-01-25 04:17:44 +01:00
|
|
|
MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
2017-01-22 22:52:36 +01:00
|
|
|
}
|
2013-02-21 03:10:33 +01:00
|
|
|
}
|
|
|
|
|
2018-01-25 04:17:44 +01:00
|
|
|
private void handleDownloadError(long messageId, long threadId, int downloadStatus, boolean automatic)
|
2013-07-17 04:52:02 +02:00
|
|
|
{
|
2013-04-26 20:23:43 +02:00
|
|
|
MmsDatabase db = DatabaseFactory.getMmsDatabase(context);
|
2012-09-30 20:46:45 +02:00
|
|
|
|
2013-07-17 04:52:02 +02:00
|
|
|
db.markDownloadState(messageId, downloadStatus);
|
2013-02-21 03:10:33 +01:00
|
|
|
|
2013-07-17 04:52:02 +02:00
|
|
|
if (automatic) {
|
|
|
|
db.markIncomingNotificationReceived(threadId);
|
2018-01-25 04:17:44 +01:00
|
|
|
MessageNotifier.updateNotification(context, threadId);
|
2013-02-21 03:10:33 +01:00
|
|
|
}
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|
2019-03-28 16:56:35 +01:00
|
|
|
|
|
|
|
public static final class Factory implements Job.Factory<MmsDownloadJob> {
|
|
|
|
@Override
|
|
|
|
public @NonNull MmsDownloadJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
|
|
|
return new MmsDownloadJob(parameters,
|
|
|
|
data.getLong(KEY_MESSAGE_ID),
|
|
|
|
data.getLong(KEY_THREAD_ID),
|
|
|
|
data.getBoolean(KEY_AUTOMATIC));
|
|
|
|
}
|
|
|
|
}
|
2011-12-20 19:20:44 +01:00
|
|
|
}
|