mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 09:49:30 +01:00
Fix handling of early receipts.
We were storing the early content under the wrong recipient.
This commit is contained in:
@@ -45,6 +45,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -128,7 +129,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||
public abstract void markGiftRedemptionFailed(long messageId);
|
||||
|
||||
public abstract Set<MessageUpdate> incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType, boolean storiesOnly);
|
||||
abstract @NonNull MmsSmsDatabase.TimestampReadResult setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead);
|
||||
|
||||
public abstract List<MarkedMessageInfo> setEntireThreadRead(long threadId);
|
||||
public abstract List<MarkedMessageInfo> setMessagesReadSince(long threadId, long timestamp);
|
||||
public abstract List<MarkedMessageInfo> setAllMessagesRead();
|
||||
@@ -276,6 +277,50 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a synchronized read message.
|
||||
* @param messageId An id representing the author-timestamp pair of the message that was read on a linked device. Note that the author could be self when
|
||||
* syncing read receipts for reactions.
|
||||
*/
|
||||
final @NonNull MmsSmsDatabase.TimestampReadResult setTimestampReadFromSyncMessage(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
||||
List<Pair<Long, Long>> expiring = new LinkedList<>();
|
||||
String[] projection = new String[] { ID, THREAD_ID, EXPIRES_IN, EXPIRE_STARTED };
|
||||
String query = getDateSentColumnName() + " = ? AND (" + RECIPIENT_ID + " = ? OR (" + RECIPIENT_ID + " = ? AND " + getOutgoingTypeClause() + "))";
|
||||
String[] args = SqlUtil.buildArgs(messageId.getTimetamp(), messageId.getRecipientId(), Recipient.self().getId());
|
||||
List<Long> threads = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = database.query(getTableName(), projection, query, args, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED));
|
||||
|
||||
expireStarted = expireStarted > 0 ? Math.min(proposedExpireStarted, expireStarted) : proposedExpireStarted;
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(READ, 1);
|
||||
values.put(REACTIONS_UNREAD, 0);
|
||||
values.put(REACTIONS_LAST_SEEN, System.currentTimeMillis());
|
||||
|
||||
if (expiresIn > 0) {
|
||||
values.put(EXPIRE_STARTED, expireStarted);
|
||||
expiring.add(new Pair<>(id, expiresIn));
|
||||
}
|
||||
|
||||
database.update(getTableName(), values, ID_WHERE, SqlUtil.buildArgs(id));
|
||||
|
||||
threads.add(threadId);
|
||||
|
||||
Long latest = threadToLatestRead.get(threadId);
|
||||
threadToLatestRead.put(threadId, (latest != null) ? Math.max(latest, messageId.getTimetamp()) : messageId.getTimetamp());
|
||||
}
|
||||
}
|
||||
|
||||
return new MmsSmsDatabase.TimestampReadResult(expiring, threads);
|
||||
}
|
||||
|
||||
private int getMessageCountForRecipientsAndType(String typeClause) {
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
||||
|
||||
@@ -1538,51 +1538,6 @@ public class MmsDatabase extends MessageDatabase {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull MmsSmsDatabase.TimestampReadResult setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
||||
List<Pair<Long, Long>> expiring = new LinkedList<>();
|
||||
String[] projection = new String[] { ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, RECIPIENT_ID };
|
||||
String query = DATE_SENT + " = ?";
|
||||
String[] args = SqlUtil.buildArgs(messageId.getTimetamp());
|
||||
List<Long> threads = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, projection, query, args, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
RecipientId theirRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
|
||||
RecipientId ourRecipientId = messageId.getRecipientId();
|
||||
|
||||
if (ourRecipientId.equals(theirRecipientId) || Recipient.resolved(theirRecipientId).isGroup() || ourRecipientId.equals(Recipient.self().getId())) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED));
|
||||
|
||||
expireStarted = expireStarted > 0 ? Math.min(proposedExpireStarted, expireStarted) : proposedExpireStarted;
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(READ, 1);
|
||||
values.put(REACTIONS_UNREAD, 0);
|
||||
values.put(REACTIONS_LAST_SEEN, System.currentTimeMillis());
|
||||
|
||||
if (expiresIn > 0) {
|
||||
values.put(EXPIRE_STARTED, expireStarted);
|
||||
expiring.add(new Pair<>(id, expiresIn));
|
||||
}
|
||||
|
||||
database.update(TABLE_NAME, values, ID_WHERE, SqlUtil.buildArgs(id));
|
||||
|
||||
threads.add(threadId);
|
||||
|
||||
Long latest = threadToLatestRead.get(threadId);
|
||||
threadToLatestRead.put(threadId, (latest != null) ? Math.max(latest, messageId.getTimetamp()) : messageId.getTimetamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new MmsSmsDatabase.TimestampReadResult(expiring, threads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Pair<RecipientId, Long> getOldestUnreadMentionDetails(long threadId) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
|
||||
|
||||
@@ -45,7 +45,6 @@ import java.io.Closeable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -617,7 +616,7 @@ public class MmsSmsDatabase extends Database {
|
||||
/**
|
||||
* @return Unhandled ids
|
||||
*/
|
||||
public Collection<SyncMessageId> setTimestampRead(@NonNull Recipient senderRecipient, @NonNull List<ReadMessage> readMessages, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
|
||||
public Collection<SyncMessageId> setTimestampReadFromSyncMessage(@NonNull List<ReadMessage> readMessages, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
|
||||
List<Pair<Long, Long>> expiringText = new LinkedList<>();
|
||||
@@ -628,12 +627,13 @@ public class MmsSmsDatabase extends Database {
|
||||
db.beginTransaction();
|
||||
try {
|
||||
for (ReadMessage readMessage : readMessages) {
|
||||
TimestampReadResult textResult = SignalDatabase.sms().setTimestampRead(new SyncMessageId(senderRecipient.getId(), readMessage.getTimestamp()),
|
||||
proposedExpireStarted,
|
||||
threadToLatestRead);
|
||||
TimestampReadResult mediaResult = SignalDatabase.mms().setTimestampRead(new SyncMessageId(senderRecipient.getId(), readMessage.getTimestamp()),
|
||||
proposedExpireStarted,
|
||||
threadToLatestRead);
|
||||
RecipientId authorId = Recipient.externalPush(readMessage.getSender()).getId();
|
||||
TimestampReadResult textResult = SignalDatabase.sms().setTimestampReadFromSyncMessage(new SyncMessageId(authorId, readMessage.getTimestamp()),
|
||||
proposedExpireStarted,
|
||||
threadToLatestRead);
|
||||
TimestampReadResult mediaResult = SignalDatabase.mms().setTimestampReadFromSyncMessage(new SyncMessageId(authorId, readMessage.getTimestamp()),
|
||||
proposedExpireStarted,
|
||||
threadToLatestRead);
|
||||
|
||||
expiringText.addAll(textResult.expiring);
|
||||
expiringMedia.addAll(mediaResult.expiring);
|
||||
@@ -642,7 +642,7 @@ public class MmsSmsDatabase extends Database {
|
||||
updatedThreads.addAll(mediaResult.threads);
|
||||
|
||||
if (textResult.threads.isEmpty() && mediaResult.threads.isEmpty()) {
|
||||
unhandled.add(new SyncMessageId(senderRecipient.getId(), readMessage.getTimestamp()));
|
||||
unhandled.add(new SyncMessageId(authorId, readMessage.getTimestamp()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -548,51 +548,6 @@ public class SmsDatabase extends MessageDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull MmsSmsDatabase.TimestampReadResult setTimestampRead(SyncMessageId messageId, long proposedExpireStarted, @NonNull Map<Long, Long> threadToLatestRead) {
|
||||
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
|
||||
List<Pair<Long, Long>> expiring = new LinkedList<>();
|
||||
String[] projection = new String[] {ID, THREAD_ID, RECIPIENT_ID, TYPE, EXPIRES_IN, EXPIRE_STARTED};
|
||||
String query = DATE_SENT + " = ?";
|
||||
String[] args = SqlUtil.buildArgs(messageId.getTimetamp());
|
||||
List<Long> threads = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = database.query(TABLE_NAME, projection, query, args, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
RecipientId theirRecipientId = messageId.getRecipientId();
|
||||
RecipientId outRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)));
|
||||
|
||||
if (outRecipientId.equals(theirRecipientId) || theirRecipientId.equals(Recipient.self().getId())) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED));
|
||||
|
||||
expireStarted = expireStarted > 0 ? Math.min(proposedExpireStarted, expireStarted) : proposedExpireStarted;
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(READ, 1);
|
||||
contentValues.put(REACTIONS_UNREAD, 0);
|
||||
contentValues.put(REACTIONS_LAST_SEEN, System.currentTimeMillis());
|
||||
|
||||
if (expiresIn > 0) {
|
||||
contentValues.put(EXPIRE_STARTED, expireStarted);
|
||||
expiring.add(new Pair<>(id, expiresIn));
|
||||
}
|
||||
|
||||
database.update(TABLE_NAME, contentValues, ID_WHERE, SqlUtil.buildArgs(id));
|
||||
|
||||
threads.add(threadId);
|
||||
|
||||
Long latest = threadToLatestRead.get(threadId);
|
||||
threadToLatestRead.put(threadId, (latest != null) ? Math.max(latest, messageId.getTimetamp()) : messageId.getTimetamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new MmsSmsDatabase.TimestampReadResult(expiring, threads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MarkedMessageInfo> setEntireThreadRead(long threadId) {
|
||||
return setMessagesRead(THREAD_ID + " = ?", new String[] {String.valueOf(threadId)});
|
||||
|
||||
Reference in New Issue
Block a user