package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.support.annotation.NonNull; 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.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; 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.Recipient; import org.thoughtcrime.securesms.util.TextSecurePreferences; 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 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, Address destination) { JobParameters.Builder builder = JobParameters.newBuilder(); builder.withPersistence(); builder.withGroupId(destination.serialize()); 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(); } protected Optional getProfileKey(@NonNull Recipient recipient) { if (!recipient.resolve().isSystemContact() && !recipient.resolve().isProfileSharing()) { return Optional.absent(); } return Optional.of(ProfileKeyUtil.getProfileKey(context)); } protected SignalServiceAddress getPushAddress(Address address) { // String relay = TextSecureDirectory.getInstance(context).getRelay(address.toPhoneString()); String relay = null; return new SignalServiceAddress(address.toPhoneString(), Optional.fromNullable(relay)); } protected List getAttachmentsFor(List parts) { List 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, attachment.getDataUri()); attachments.add(SignalServiceAttachment.newStreamBuilder() .withStream(is) .withContentType(attachment.getContentType()) .withLength(attachment.getSize()) .withFileName(attachment.getFileName()) .withVoiceNote(attachment.isVoiceNote()) .withWidth(attachment.getWidth()) .withHeight(attachment.getHeight()) .withListener((total, 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); Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId); if (threadId != -1 && recipient != null) { MessageNotifier.notifyMessageDeliveryFailed(context, recipient, threadId); } } protected abstract void onPushSend() throws Exception; }