package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.util.Log; import org.greenrobot.eventbus.EventBus; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.TextSecureExpiredException; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.TextSecureDirectory; import org.thoughtcrime.securesms.events.PartProgressEvent; import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; import org.whispersystems.signalservice.api.messages.SignalServiceAttachment.ProgressListener; import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.util.InvalidNumberException; import java.io.IOException; import java.io.InputStream; import java.util.LinkedList; import java.util.List; public abstract class PushSendJob extends SendJob { private static final String TAG = PushSendJob.class.getSimpleName(); protected PushSendJob(Context context, JobParameters parameters) { super(context, parameters); } protected static JobParameters constructParameters(Context context, String destination) { JobParameters.Builder builder = JobParameters.newBuilder(); builder.withPersistence(); builder.withGroupId(destination); builder.withRequirement(new MasterSecretRequirement(context)); builder.withRequirement(new NetworkRequirement(context)); builder.withRetryCount(5); return builder.create(); } @Override protected final void onSend(MasterSecret masterSecret) throws Exception { if (TextSecurePreferences.getSignedPreKeyFailureCount(context) > 5) { ApplicationContext.getInstance(context) .getJobManager() .add(new RotateSignedPreKeyJob(context)); throw new TextSecureExpiredException("Too many signed prekey rotation failures"); } onPushSend(masterSecret); } protected SignalServiceAddress getPushAddress(String number) throws InvalidNumberException { String e164number = Util.canonicalizeNumber(context, number); String relay = TextSecureDirectory.getInstance(context).getRelay(e164number); return new SignalServiceAddress(e164number, Optional.fromNullable(relay)); } protected List<SignalServiceAttachment> getAttachmentsFor(MasterSecret masterSecret, List<Attachment> parts) { List<SignalServiceAttachment> attachments = new LinkedList<>(); for (final Attachment attachment : parts) { try { if (attachment.getDataUri() == null || attachment.getSize() == 0) throw new IOException("Assertion failed, outgoing attachment has no data!"); InputStream is = PartAuthority.getAttachmentStream(context, masterSecret, attachment.getDataUri()); attachments.add(SignalServiceAttachment.newStreamBuilder() .withStream(is) .withContentType(attachment.getContentType()) .withLength(attachment.getSize()) .withFileName(attachment.getFileName()) .withVoiceNote(attachment.isVoiceNote()) .withListener(new ProgressListener() { @Override public void onAttachmentProgress(long total, long progress) { EventBus.getDefault().postSticky(new PartProgressEvent(attachment, total, progress)); } }) .build()); } catch (IOException ioe) { Log.w(TAG, "Couldn't open attachment", ioe); } } return attachments; } protected void notifyMediaMessageDeliveryFailed(Context context, long messageId) { long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId); Recipients recipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(threadId); if (threadId != -1 && recipients != null) { MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId); } } protected abstract void onPushSend(MasterSecret masterSecret) throws Exception; }