That fuck shit the fascists are using
1package org.tm.archive.database;
2
3import android.content.ContentValues;
4import android.content.Context;
5import android.database.Cursor;
6import android.text.TextUtils;
7
8import androidx.annotation.NonNull;
9import androidx.annotation.Nullable;
10
11import com.annimon.stream.Stream;
12
13import org.tm.archive.database.model.Mention;
14import org.tm.archive.recipients.RecipientId;
15import org.signal.core.util.CursorUtil;
16import org.signal.core.util.SqlUtil;
17
18import java.util.Collection;
19import java.util.HashMap;
20import java.util.LinkedList;
21import java.util.List;
22import java.util.Map;
23
24public class MentionTable extends DatabaseTable implements RecipientIdDatabaseReference, ThreadIdDatabaseReference {
25
26 public static final String TABLE_NAME = "mention";
27
28 private static final String ID = "_id";
29 static final String THREAD_ID = "thread_id";
30 public static final String MESSAGE_ID = "message_id";
31 static final String RECIPIENT_ID = "recipient_id";
32 private static final String RANGE_START = "range_start";
33 private static final String RANGE_LENGTH = "range_length";
34
35 public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + "(" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
36 THREAD_ID + " INTEGER, " +
37 MESSAGE_ID + " INTEGER, " +
38 RECIPIENT_ID + " INTEGER, " +
39 RANGE_START + " INTEGER, " +
40 RANGE_LENGTH + " INTEGER)";
41
42 public static final String[] CREATE_INDEXES = new String[] {
43 "CREATE INDEX IF NOT EXISTS mention_message_id_index ON " + TABLE_NAME + " (" + MESSAGE_ID + ");",
44 "CREATE INDEX IF NOT EXISTS mention_recipient_id_thread_id_index ON " + TABLE_NAME + " (" + RECIPIENT_ID + ", " + THREAD_ID + ");"
45 };
46
47 public MentionTable(@NonNull Context context, @NonNull SignalDatabase databaseHelper) {
48 super(context, databaseHelper);
49 }
50
51 public void insert(long threadId, long messageId, @NonNull Collection<Mention> mentions) {
52 SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
53
54 db.beginTransaction();
55 try {
56 for (Mention mention : mentions) {
57 ContentValues values = new ContentValues();
58 values.put(THREAD_ID, threadId);
59 values.put(MESSAGE_ID, messageId);
60 values.put(RECIPIENT_ID, mention.getRecipientId().toLong());
61 values.put(RANGE_START, mention.getStart());
62 values.put(RANGE_LENGTH, mention.getLength());
63 db.insert(TABLE_NAME, null, values);
64 }
65
66 db.setTransactionSuccessful();
67 } finally {
68 db.endTransaction();
69 }
70 }
71
72 public @NonNull List<Mention> getMentionsForMessage(long messageId) {
73 SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
74 List<Mention> mentions = new LinkedList<>();
75
76 try (Cursor cursor = db.query(TABLE_NAME, null, MESSAGE_ID + " = ?", SqlUtil.buildArgs(messageId), null, null, null)) {
77 while (cursor != null && cursor.moveToNext()) {
78 mentions.add(new Mention(RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)),
79 CursorUtil.requireInt(cursor, RANGE_START),
80 CursorUtil.requireInt(cursor, RANGE_LENGTH)));
81 }
82 }
83
84 return mentions;
85 }
86
87 public @NonNull Map<Long, List<Mention>> getMentionsForMessages(@NonNull Collection<Long> messageIds) {
88 SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
89 String ids = TextUtils.join(",", messageIds);
90
91 try (Cursor cursor = db.query(TABLE_NAME, null, MESSAGE_ID + " IN (" + ids + ")", null, null, null, null)) {
92 return readMentions(cursor);
93 }
94 }
95
96 public @NonNull Map<Long, List<Mention>> getMentionsContainingRecipients(@NonNull Collection<RecipientId> recipientIds, long limit) {
97 return getMentionsContainingRecipients(recipientIds, -1, limit);
98 }
99
100 public @NonNull Map<Long, List<Mention>> getMentionsContainingRecipients(@NonNull Collection<RecipientId> recipientIds, long threadId, long limit) {
101 SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
102 String ids = TextUtils.join(",", Stream.of(recipientIds).map(RecipientId::serialize).toList());
103
104 String where = " WHERE " + RECIPIENT_ID + " IN (" + ids + ")";
105 if (threadId != -1) {
106 where += " AND " + THREAD_ID + " = " + threadId;
107 }
108
109 String subSelect = "SELECT DISTINCT " + MESSAGE_ID +
110 " FROM " + TABLE_NAME +
111 where +
112 " ORDER BY " + ID + " DESC" +
113 " LIMIT " + limit;
114
115 String query = "SELECT *" +
116 " FROM " + TABLE_NAME +
117 " WHERE " + MESSAGE_ID +
118 " IN (" + subSelect + ")";
119
120 try (Cursor cursor = db.rawQuery(query, null)) {
121 return readMentions(cursor);
122 }
123 }
124
125 void deleteMentionsForMessage(long messageId) {
126 SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
127 String where = MESSAGE_ID + " = ?";
128
129 db.delete(TABLE_NAME, where, SqlUtil.buildArgs(messageId));
130 }
131
132 void deleteAbandonedMentions() {
133 SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
134 String where = MESSAGE_ID + " NOT IN (SELECT " + MessageTable.ID + " FROM " + MessageTable.TABLE_NAME + ") OR " + THREAD_ID + " NOT IN (SELECT " + ThreadTable.ID + " FROM " + ThreadTable.TABLE_NAME + " WHERE " + ThreadTable.ACTIVE + " = 1)";
135
136 db.delete(TABLE_NAME, where, null);
137 }
138
139 void deleteAllMentions() {
140 SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
141 db.delete(TABLE_NAME, null, null);
142 }
143
144 private @NonNull Map<Long, List<Mention>> readMentions(@Nullable Cursor cursor) {
145 Map<Long, List<Mention>> mentions = new HashMap<>();
146 while (cursor != null && cursor.moveToNext()) {
147 long messageId = CursorUtil.requireLong(cursor, MESSAGE_ID);
148 List<Mention> messageMentions = mentions.get(messageId);
149
150 if (messageMentions == null) {
151 messageMentions = new LinkedList<>();
152 mentions.put(messageId, messageMentions);
153 }
154
155 messageMentions.add(new Mention(RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)),
156 CursorUtil.requireInt(cursor, RANGE_START),
157 CursorUtil.requireInt(cursor, RANGE_LENGTH)));
158 }
159 return mentions;
160 }
161
162 @Override
163 public void remapRecipient(@NonNull RecipientId fromId, @NonNull RecipientId toId) {
164 ContentValues values = new ContentValues();
165 values.put(RECIPIENT_ID, toId.serialize());
166 getWritableDatabase().update(TABLE_NAME, values, RECIPIENT_ID + " = ?", SqlUtil.buildArgs(fromId));
167 }
168
169 @Override
170 public void remapThread(long fromId, long toId) {
171 ContentValues values = new ContentValues();
172 values.put(MentionTable.THREAD_ID, toId);
173
174 getWritableDatabase().update(TABLE_NAME, values, THREAD_ID + " = ?", SqlUtil.buildArgs(fromId));
175 }
176}