That fuck shit the fascists are using
1package org.tm.archive.service;
2
3import android.app.Application;
4import android.content.BroadcastReceiver;
5import android.content.Context;
6import android.content.Intent;
7
8import androidx.annotation.AnyThread;
9import androidx.annotation.NonNull;
10import androidx.annotation.Nullable;
11import androidx.annotation.WorkerThread;
12
13import org.signal.core.util.logging.Log;
14import org.tm.archive.database.MessageTable;
15import org.tm.archive.database.PendingRetryReceiptCache;
16import org.tm.archive.database.SignalDatabase;
17import org.tm.archive.database.model.PendingRetryReceiptModel;
18import org.tm.archive.dependencies.ApplicationDependencies;
19
20import java.util.concurrent.TimeUnit;
21
22
23/**
24 * Manages the time-based creation of error messages for retries that are pending for messages we couldn't decrypt.
25 */
26public final class PendingRetryReceiptManager extends TimedEventManager<PendingRetryReceiptModel> {
27
28 private static final String TAG = Log.tag(PendingRetryReceiptManager.class);
29
30 private static final long RETRY_RECEIPT_LIFESPAN = TimeUnit.HOURS.toMillis(1);
31
32 private final PendingRetryReceiptCache pendingCache;
33 private final MessageTable messageDatabase;
34
35 public PendingRetryReceiptManager(@NonNull Application application) {
36 super(application, "PendingRetryReceiptManager");
37
38 this.pendingCache = ApplicationDependencies.getPendingRetryReceiptCache();
39 this.messageDatabase = SignalDatabase.messages();
40
41 scheduleIfNecessary();
42 }
43
44 @WorkerThread
45 @Override
46 protected @Nullable PendingRetryReceiptModel getNextClosestEvent() {
47 PendingRetryReceiptModel model = pendingCache.getOldest();
48
49 if (model != null) {
50 Log.i(TAG, "Next closest expiration is in " + getDelayForEvent(model) + " ms for timestamp " + model.getSentTimestamp() + ".");
51 } else {
52 Log.d(TAG, "No pending receipts to schedule.");
53 }
54
55 return model;
56 }
57
58 @WorkerThread
59 @Override
60 protected void executeEvent(@NonNull PendingRetryReceiptModel event) {
61 if (SignalDatabase.messages().messageExists(event.getSentTimestamp(), event.getAuthor())) {
62 Log.w(TAG, "[" + event.getSentTimestamp() + "] We have since received the target message! No longer need to insert an error.");
63 } else if (!SignalDatabase.threads().containsId(event.getThreadId())) {
64 Log.w(TAG, "[" + event.getSentTimestamp() + "] Would normally show an error, but the thread has since been deleted! ThreadId: " + event.getThreadId());
65 } else if (!SignalDatabase.recipients().containsId(event.getAuthor())) {
66 Log.w(TAG, "[" + event.getSentTimestamp() + "] Would normally show an error, but the recipient has since been deleted! RecipientId: " + event.getAuthor());
67 } else {
68 Log.w(TAG, "[" + event.getSentTimestamp() + "] It's been " + (System.currentTimeMillis() - event.getReceivedTimestamp()) + " ms since this retry receipt was received. Showing an error.");
69 messageDatabase.insertBadDecryptMessage(event.getAuthor(), event.getAuthorDevice(), event.getSentTimestamp() - 1, event.getReceivedTimestamp(), event.getThreadId());
70 }
71
72 pendingCache.delete(event);
73 }
74
75 @WorkerThread
76 @Override
77 protected long getDelayForEvent(@NonNull PendingRetryReceiptModel event) {
78 long expiresAt = event.getReceivedTimestamp() + RETRY_RECEIPT_LIFESPAN;
79 long timeLeft = expiresAt - System.currentTimeMillis();
80
81 return Math.max(0, timeLeft);
82 }
83
84 @AnyThread
85 @Override
86 protected void scheduleAlarm(@NonNull Application application, PendingRetryReceiptModel event, long delay) {
87 setAlarm(application, delay, PendingRetryReceiptAlarm.class);
88 }
89
90 public static class PendingRetryReceiptAlarm extends BroadcastReceiver {
91
92 private static final String TAG = Log.tag(PendingRetryReceiptAlarm.class);
93
94 @Override
95 public void onReceive(Context context, Intent intent) {
96 Log.d(TAG, "onReceive()");
97 ApplicationDependencies.getPendingRetryReceiptManager().scheduleIfNecessary();
98 }
99 }
100}