From 3179808f1786c6c253757dbf82eafe802134c4bb Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Fri, 2 Oct 2020 11:24:59 -0400 Subject: [PATCH] Cleanup mentions with bad thread ids or ranges, or duplicates. --- .../securesms/database/MentionUtil.java | 8 ++-- .../database/helpers/SQLCipherOpenHelper.java | 39 ++++++++++++++++++- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java index b3b9a37bc..d93f25cb1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MentionUtil.java @@ -16,7 +16,6 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.MentionSetting; import org.thoughtcrime.securesms.database.model.Mention; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList; -import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.whispersystems.signalservice.api.util.UuidUtil; @@ -24,6 +23,8 @@ import org.whispersystems.signalservice.api.util.UuidUtil; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; public final class MentionUtil { @@ -68,14 +69,13 @@ public final class MentionUtil { return new UpdatedBodyAndMentions(body, mentions); } + SortedSet sortedMentions = new TreeSet<>(mentions); SpannableStringBuilder updatedBody = new SpannableStringBuilder(); List updatedMentions = new ArrayList<>(); - Collections.sort(mentions); - int bodyIndex = 0; - for (Mention mention : mentions) { + for (Mention mention : sortedMentions) { updatedBody.append(body.subSequence(bodyIndex, mention.getStart())); CharSequence replaceWith = replacementTextGenerator.apply(mention); Mention updatedMention = new Mention(mention.getRecipientId(), updatedBody.length(), replaceWith.length()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java index b544ca339..38095df4e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SQLCipherOpenHelper.java @@ -62,14 +62,17 @@ import org.thoughtcrime.securesms.util.FileUtils; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.SqlUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.thoughtcrime.securesms.util.Triple; import org.thoughtcrime.securesms.util.Util; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; public class SQLCipherOpenHelper extends SQLiteOpenHelper { @@ -151,8 +154,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final int THUMBNAIL_CLEANUP = 74; private static final int STICKER_CONTENT_TYPE_CLEANUP = 75; private static final int MENTION_CLEANUP = 76; + private static final int MENTION_CLEANUP_V2 = 77; - private static final int DATABASE_VERSION = 76; + private static final int DATABASE_VERSION = 77; private static final String DATABASE_NAME = "signal.db"; private final Context context; @@ -1086,6 +1090,39 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper { } } + if (oldVersion < MENTION_CLEANUP_V2) { + String selectMentionIdsWithMismatchingThreadIds = "select mention._id from mention left join mms on mention.message_id = mms._id where mention.thread_id != mms.thread_id"; + db.delete("mention", "_id in (" + selectMentionIdsWithMismatchingThreadIds + ")", null); + + List idsToDelete = new LinkedList<>(); + Set> mentionTuples = new HashSet<>(); + try (Cursor cursor = db.rawQuery("select mention.*, mms.body from mention inner join mms on mention.message_id = mms._id order by mention._id desc", null)) { + while (cursor != null && cursor.moveToNext()) { + long mentionId = CursorUtil.requireLong(cursor, "_id"); + long messageId = CursorUtil.requireLong(cursor, "message_id"); + int rangeStart = CursorUtil.requireInt(cursor, "range_start"); + int rangeLength = CursorUtil.requireInt(cursor, "range_length"); + String body = CursorUtil.requireString(cursor, "body"); + + if (body != null && rangeStart < body.length() && body.charAt(rangeStart) != '\uFFFC') { + idsToDelete.add(mentionId); + } else { + Triple tuple = new Triple<>(messageId, rangeStart, rangeLength); + if (mentionTuples.contains(tuple)) { + idsToDelete.add(mentionId); + } else { + mentionTuples.add(tuple); + } + } + } + + if (Util.hasItems(idsToDelete)) { + String ids = TextUtils.join(",", idsToDelete); + db.delete("mention", "_id in (" + ids + ")", null); + } + } + } + db.setTransactionSuccessful(); } finally { db.endTransaction();