Merge branch 'mlin/PR/InvisiblePlaceholders' into release/5.19.0
This commit is contained in:
commit
eec4d68ee1
@ -81,6 +81,7 @@
|
||||
"InteractionRecord.hasEnded": 56,
|
||||
"InteractionRecord.hasLegacyMessageState": 22,
|
||||
"InteractionRecord.hasSyncedTranscript": 23,
|
||||
"InteractionRecord.hiddenUntilTimestamp": 65,
|
||||
"InteractionRecord.infoMessageUserInfo": 50,
|
||||
"InteractionRecord.isFromLinkedDevice": 24,
|
||||
"InteractionRecord.isLocalChange": 25,
|
||||
|
||||
@ -163,8 +163,8 @@ public class CVMessageMapping: NSObject {
|
||||
owsAssertDebug(count > 0)
|
||||
let count = max(1, min(count, maxInteractionCount))
|
||||
|
||||
// The number of interactions currently in the conversation.
|
||||
let conversationSize = interactionFinder.count(transaction: transaction)
|
||||
// The number of visible interactions currently in the conversation.
|
||||
let conversationSize = interactionFinder.count(includingHiddenInteractions: false, transaction: transaction)
|
||||
guard conversationSize > 0 else {
|
||||
self.loadedInteractions = []
|
||||
updateCanLoadMore(fetchIndexSet: IndexSet(), conversationSize: conversationSize)
|
||||
@ -190,7 +190,10 @@ public class CVMessageMapping: NSObject {
|
||||
// the distance from the oldest message, since most of the time the user will
|
||||
// be scrolled towards the bottom of the conversation. The further you scroll
|
||||
// from the bottom of the conversation, the more expensive this query will get.
|
||||
guard let distanceFromLatest = try self.interactionFinder.distanceFromLatest(interactionUniqueId: interactionUniqueId, transaction: transaction) else {
|
||||
guard let distanceFromLatest = try self.interactionFinder.distanceFromLatest(
|
||||
interactionUniqueId: interactionUniqueId,
|
||||
includingHiddenInteractions: false,
|
||||
transaction: transaction) else {
|
||||
throw OWSAssertionError("viewIndex was unexpectedly nil")
|
||||
}
|
||||
return Int(conversationSize - distanceFromLatest - 1)
|
||||
@ -474,6 +477,7 @@ public class CVMessageMapping: NSObject {
|
||||
|
||||
var newItems: [TSInteraction] = []
|
||||
try self.interactionFinder.enumerateInteractions(range: nsRange,
|
||||
includingHiddenInteractions: DebugFlags.showFailedDecryptionPlaceholders.get(),
|
||||
transaction: transaction) { (interaction: TSInteraction, _) in
|
||||
newItems.append(interaction)
|
||||
}
|
||||
@ -483,7 +487,10 @@ public class CVMessageMapping: NSObject {
|
||||
// Loading the mapping from the cache has the following steps:
|
||||
//
|
||||
// 1. Fetch the uniqueIds for the interactions in the load window/mapping.
|
||||
let interactionIds = try interactionFinder.interactionIds(inRange: nsRange, transaction: transaction)
|
||||
let interactionIds = try interactionFinder.interactionIds(
|
||||
inRange: nsRange,
|
||||
includingHiddenInteractions: DebugFlags.showFailedDecryptionPlaceholders.get(),
|
||||
transaction: transaction)
|
||||
guard !interactionIds.isEmpty else {
|
||||
return []
|
||||
}
|
||||
|
||||
@ -1663,6 +1663,9 @@
|
||||
/* Error message for a decryption failure. Embeds {{sender short name}}. */
|
||||
"ERROR_MESSAGE_DECRYPTION_FAILURE" = "A message from %@ could not be delivered";
|
||||
|
||||
/* Error message for a decryption failure. */
|
||||
"ERROR_MESSAGE_DECRYPTION_FAILURE_UNKNOWN_SENDER" = "A message could not be delivered";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"ERROR_MESSAGE_DUPLICATE_MESSAGE" = "Received a duplicate message.";
|
||||
|
||||
|
||||
@ -692,6 +692,8 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
|
||||
}
|
||||
|
||||
public func notifyUser(for errorMessage: TSErrorMessage, thread: TSThread, transaction: SDSAnyWriteTransaction) {
|
||||
guard (errorMessage is OWSRecoverableDecryptionPlaceholder) == false else { return }
|
||||
|
||||
switch errorMessage.errorType {
|
||||
case .noSession,
|
||||
.wrongTrustedIdentityKey,
|
||||
|
||||
@ -115,6 +115,7 @@ CREATE
|
||||
,"paymentRequest" BLOB
|
||||
,"viewed" BOOLEAN
|
||||
,"serverGuid" TEXT
|
||||
,"hiddenUntilTimestamp" INTEGER
|
||||
)
|
||||
;
|
||||
|
||||
|
||||
@ -357,7 +357,9 @@ lastVisibleSortIdOnScreenPercentageObsolete:(double)lastVisibleSortIdOnScreenPer
|
||||
- (NSUInteger)numberOfInteractionsWithTransaction:(SDSAnyReadTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(transaction);
|
||||
return [[[InteractionFinder alloc] initWithThreadUniqueId:self.uniqueId] countWithTransaction:transaction];
|
||||
return
|
||||
[[[InteractionFinder alloc] initWithThreadUniqueId:self.uniqueId] countIncludingHiddenInteractions:YES
|
||||
transaction:transaction];
|
||||
}
|
||||
|
||||
- (nullable TSInteraction *)lastInteractionForInboxWithTransaction:(SDSAnyReadTransaction *)transaction
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSDisappearingConfigurationUpdateInfoMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSVerificationStateChangeMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSErrorMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,6 +129,11 @@ NS_DESIGNATED_INITIALIZER NS_SWIFT_NAME(init(grdbId:uniqueId:receivedAtTimestamp
|
||||
groupId:(nullable NSData *)groupId
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction;
|
||||
|
||||
+ (instancetype)failedDecryptionForSender:(nullable SignalServiceAddress *)sender
|
||||
thread:(TSThread *)thread
|
||||
timestamp:(uint64_t)timestamp
|
||||
transaction:(SDSAnyWriteTransaction *)transaction;
|
||||
|
||||
@property (nonatomic, readonly) TSErrorMessageType errorType;
|
||||
@property (nullable, nonatomic, readonly) SignalServiceAddress *sender;
|
||||
@property (nullable, nonatomic, readonly) SignalServiceAddress *recipientAddress;
|
||||
|
||||
@ -232,11 +232,16 @@ NSUInteger TSErrorMessageSchemaVersion = 2;
|
||||
return NSLocalizedString(
|
||||
@"ERROR_MESSAGE_SESSION_REFRESH", @"Text notifying the user that their secure session has been reset");
|
||||
case TSErrorMessageDecryptionFailure: {
|
||||
NSString *formatString = NSLocalizedString(@"ERROR_MESSAGE_DECRYPTION_FAILURE",
|
||||
@"Error message for a decryption failure. Embeds {{sender short name}}.");
|
||||
NSString *senderName = [self.contactsManager shortDisplayNameForAddress:self.sender
|
||||
transaction:transaction];
|
||||
return [[NSString alloc] initWithFormat:formatString, senderName];
|
||||
if (self.sender) {
|
||||
NSString *formatString = NSLocalizedString(@"ERROR_MESSAGE_DECRYPTION_FAILURE",
|
||||
@"Error message for a decryption failure. Embeds {{sender short name}}.");
|
||||
NSString *senderName = [self.contactsManager shortDisplayNameForAddress:self.sender
|
||||
transaction:transaction];
|
||||
return [[NSString alloc] initWithFormat:formatString, senderName];
|
||||
} else {
|
||||
return NSLocalizedString(
|
||||
@"ERROR_MESSAGE_DECRYPTION_FAILURE_UNKNOWN_SENDER", @"Error message for a decryption failure.");
|
||||
}
|
||||
}
|
||||
default:
|
||||
OWSFailDebug(@"failure: unknown error type");
|
||||
@ -296,6 +301,18 @@ NSUInteger TSErrorMessageSchemaVersion = 2;
|
||||
return [builder build];
|
||||
}
|
||||
|
||||
+ (instancetype)failedDecryptionForSender:(nullable SignalServiceAddress *)sender
|
||||
thread:(TSThread *)thread
|
||||
timestamp:(uint64_t)timestamp
|
||||
transaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
TSErrorMessageBuilder *builder =
|
||||
[TSErrorMessageBuilder errorMessageBuilderWithThread:thread errorType:TSErrorMessageDecryptionFailure];
|
||||
builder.senderAddress = sender;
|
||||
builder.timestamp = timestamp;
|
||||
return [builder build];
|
||||
}
|
||||
|
||||
+ (instancetype)failedDecryptionForEnvelope:(SSKProtoEnvelope *)envelope
|
||||
groupId:(nullable NSData *)groupId
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
@ -318,11 +335,7 @@ NSUInteger TSErrorMessageSchemaVersion = 2;
|
||||
if (!thread) {
|
||||
return nil;
|
||||
}
|
||||
TSErrorMessageBuilder *builder =
|
||||
[TSErrorMessageBuilder errorMessageBuilderWithThread:thread errorType:TSErrorMessageDecryptionFailure];
|
||||
builder.senderAddress = sender;
|
||||
builder.timestamp = envelope.timestamp;
|
||||
return [builder build];
|
||||
return [self failedDecryptionForSender:sender thread:thread timestamp:envelope.timestamp transaction:transaction];
|
||||
}
|
||||
|
||||
#pragma mark - OWSReadTracking
|
||||
|
||||
@ -125,7 +125,8 @@ class TSIncomingMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = model.wasViewed
|
||||
let serverGuid: String? = model.serverGuid
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSInfoMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,6 +92,7 @@ public struct InteractionRecord: SDSRecord {
|
||||
public let paymentRequest: Data?
|
||||
public let viewed: Bool?
|
||||
public let serverGuid: String?
|
||||
public let hiddenUntilTimestamp: UInt64?
|
||||
|
||||
public enum CodingKeys: String, CodingKey, ColumnExpression, CaseIterable {
|
||||
case id
|
||||
@ -161,6 +162,7 @@ public struct InteractionRecord: SDSRecord {
|
||||
case paymentRequest
|
||||
case viewed
|
||||
case serverGuid
|
||||
case hiddenUntilTimestamp
|
||||
}
|
||||
|
||||
public static func columnName(_ column: InteractionRecord.CodingKeys, fullyQualified: Bool = false) -> String {
|
||||
@ -251,6 +253,7 @@ public extension InteractionRecord {
|
||||
paymentRequest = row[64]
|
||||
viewed = row[65]
|
||||
serverGuid = row[66]
|
||||
hiddenUntilTimestamp = row[67]
|
||||
}
|
||||
}
|
||||
|
||||
@ -625,6 +628,7 @@ extension TSInteraction {
|
||||
let senderSerialized: Data? = record.sender
|
||||
let sender: SignalServiceAddress? = try SDSDeserialization.optionalUnarchive(senderSerialized, name: "sender")
|
||||
let wasIdentityVerified: Bool = try SDSDeserialization.required(record.wasIdentityVerified, name: "wasIdentityVerified")
|
||||
let hiddenUntilTimestamp: UInt64 = try SDSDeserialization.required(record.hiddenUntilTimestamp, name: "hiddenUntilTimestamp")
|
||||
|
||||
return OWSRecoverableDecryptionPlaceholder(grdbId: recordId,
|
||||
uniqueId: uniqueId,
|
||||
@ -650,7 +654,8 @@ extension TSInteraction {
|
||||
read: read,
|
||||
recipientAddress: recipientAddress,
|
||||
sender: sender,
|
||||
wasIdentityVerified: wasIdentityVerified)
|
||||
wasIdentityVerified: wasIdentityVerified,
|
||||
hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
|
||||
case .unknownContactBlockOfferMessage:
|
||||
|
||||
@ -3546,6 +3551,7 @@ extension TSInteraction: DeepCopyable {
|
||||
sender = nil
|
||||
}
|
||||
let wasIdentityVerified: Bool = modelToCopy.wasIdentityVerified
|
||||
let hiddenUntilTimestamp: UInt64 = modelToCopy.hiddenUntilTimestamp
|
||||
|
||||
return OWSRecoverableDecryptionPlaceholder(grdbId: id,
|
||||
uniqueId: uniqueId,
|
||||
@ -3571,7 +3577,8 @@ extension TSInteraction: DeepCopyable {
|
||||
read: read,
|
||||
recipientAddress: recipientAddress,
|
||||
sender: sender,
|
||||
wasIdentityVerified: wasIdentityVerified)
|
||||
wasIdentityVerified: wasIdentityVerified,
|
||||
hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
|
||||
if let modelToCopy = self as? TSErrorMessage {
|
||||
@ -3974,6 +3981,7 @@ extension TSInteractionSerializer {
|
||||
static let paymentRequestColumn = SDSColumnMetadata(columnName: "paymentRequest", columnType: .blob, isOptional: true)
|
||||
static let viewedColumn = SDSColumnMetadata(columnName: "viewed", columnType: .int, isOptional: true)
|
||||
static let serverGuidColumn = SDSColumnMetadata(columnName: "serverGuid", columnType: .unicodeString, isOptional: true)
|
||||
static let hiddenUntilTimestampColumn = SDSColumnMetadata(columnName: "hiddenUntilTimestamp", columnType: .int64, isOptional: true)
|
||||
|
||||
// TODO: We should decide on a naming convention for
|
||||
// tables that store models.
|
||||
@ -4046,7 +4054,8 @@ extension TSInteractionSerializer {
|
||||
paymentNotificationColumn,
|
||||
paymentRequestColumn,
|
||||
viewedColumn,
|
||||
serverGuidColumn
|
||||
serverGuidColumn,
|
||||
hiddenUntilTimestampColumn
|
||||
])
|
||||
}
|
||||
|
||||
@ -4520,8 +4529,9 @@ class TSInteractionSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -56,10 +56,9 @@ extension TSInteraction {
|
||||
// there was no meaningful interaction.
|
||||
return false
|
||||
case .decryptionFailure:
|
||||
if let replaceableInteraction = errorMessage as? OWSRecoverableDecryptionPlaceholder {
|
||||
// Replaceable interactions may be temporarily hidden if we expect we'll be
|
||||
// able to recover
|
||||
return replaceableInteraction.isVisible
|
||||
if errorMessage is OWSRecoverableDecryptionPlaceholder {
|
||||
// Replaceable interactions should never be shown to the user
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
@ -119,40 +118,9 @@ extension TSInteraction {
|
||||
if placeholder.supportsReplacement {
|
||||
placeholder.replaceWithInteraction(self, writeTx: transaction)
|
||||
return true
|
||||
} else if placeholder.uniqueThreadId == uniqueThreadId {
|
||||
// We've found the placeholder for the replacement message, but it is no longer eligible
|
||||
// for replacement. We now want to preserve this placeholder as a permanent error message.
|
||||
//
|
||||
// In many places we assume interaction timestamps are unique for a thread. So we adjust the timestamp
|
||||
// to preserve this uniqueness. It's likely nothing will collide, but we walk back over a small window
|
||||
// to find an opening just in case.
|
||||
let timestampWindow = (placeholder.timestamp - 10 ..< placeholder.timestamp).reversed()
|
||||
|
||||
let newTimestamp = timestampWindow.first { candidate in
|
||||
guard candidate > 0 else { return false }
|
||||
|
||||
do {
|
||||
return try InteractionFinder.interactions(withTimestamp: candidate, filter: { interaction in
|
||||
interaction.uniqueThreadId == placeholder.uniqueThreadId
|
||||
}, transaction: transaction).isEmpty
|
||||
} catch {
|
||||
owsFailDebug("\(error)")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if let newTimestamp = newTimestamp, newTimestamp > 0 {
|
||||
Logger.info("Placeholder not eligible for replacement. Updating timestamp")
|
||||
placeholder.anyUpdate(transaction: transaction) { interaction in
|
||||
(interaction as? OWSRecoverableDecryptionPlaceholder)?.adjustTimestamp(newTimestamp)
|
||||
}
|
||||
} else {
|
||||
Logger.warn("Placeholder not eligible for replacement. Failed to find free timestamp. Deleting placeholder.")
|
||||
placeholder.anyRemove(transaction: transaction)
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
Logger.info("Placeholder not eligible for replacement. No need to adjust timestamp")
|
||||
Logger.info("Placeholder not eligible for replacement, deleting.")
|
||||
placeholder.anyRemove(transaction: transaction)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSOutgoingMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSUnreadIndicatorInteractionSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSInvalidIdentityKeyErrorMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSInvalidIdentityKeyReceivingErrorMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSInvalidIdentityKeySendingErrorMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSAddToContactsOfferMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSAddToProfileWhitelistOfferMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSGroupCallMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +51,9 @@ public class OWSMessageDecryptResult: NSObject {
|
||||
public class OWSMessageDecrypter: OWSMessageHandler {
|
||||
|
||||
private var senderIdsResetDuringCurrentBatch = NSMutableSet()
|
||||
private var placeholderCleanupTimer: Timer? {
|
||||
didSet { oldValue?.invalidate() }
|
||||
}
|
||||
|
||||
public override init() {
|
||||
super.init()
|
||||
@ -63,6 +66,12 @@ public class OWSMessageDecrypter: OWSMessageHandler {
|
||||
name: MessageProcessor.messageProcessorDidFlushQueue,
|
||||
object: nil
|
||||
)
|
||||
|
||||
AppReadiness.runNowOrWhenAppDidBecomeReadySync { [weak self] in
|
||||
self?.databaseStorage.read { [weak self] readTx in
|
||||
self?.schedulePlaceholderCleanup(transaction: readTx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func decryptEnvelope(_ envelope: SSKProtoEnvelope, envelopeData: Data, transaction: SDSAnyWriteTransaction) -> Result<OWSMessageDecryptResult, Error> {
|
||||
@ -768,6 +777,59 @@ public class OWSMessageDecrypter: OWSMessageHandler {
|
||||
return error
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
func schedulePlaceholderCleanup(transaction readTx: SDSAnyReadTransaction) {
|
||||
guard let oldestPlaceholder = GRDBInteractionFinder.oldestPlaceholderInteraction(transaction: readTx.unwrapGrdbRead) else { return }
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if oldestPlaceholder.expirationDate.isBeforeNow {
|
||||
Logger.info("Oldest placeholder expirationDate: \(oldestPlaceholder.expirationDate). Will perform cleanup...")
|
||||
self.placeholderCleanupTimer = nil
|
||||
self.cleanupExpiredPlaceholders()
|
||||
|
||||
} else if (self.placeholderCleanupTimer?.fireDate ?? .distantFuture).isAfter(oldestPlaceholder.expirationDate) {
|
||||
Logger.info("Oldest placeholder expirationDate: \(oldestPlaceholder.expirationDate). Scheduling timer...")
|
||||
|
||||
self.placeholderCleanupTimer = Timer.scheduledTimer(
|
||||
withTimeInterval: oldestPlaceholder.expirationDate.timeIntervalSinceNow,
|
||||
repeats: false,
|
||||
block: { [weak self] _ in
|
||||
self?.cleanupExpiredPlaceholders()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cleanupExpiredPlaceholders() {
|
||||
databaseStorage.asyncWrite { writeTx in
|
||||
Logger.info("Performing placeholder cleanup")
|
||||
GRDBInteractionFinder.enumeratePlaceholders(transaction: writeTx.unwrapGrdbWrite) { placeholder, _ in
|
||||
if placeholder.expirationDate.isBeforeNow {
|
||||
Logger.info("replacing placeholder \(placeholder.timestamp) with error message")
|
||||
|
||||
let thread = placeholder.thread(transaction: writeTx)
|
||||
let errorMessage = TSErrorMessage.failedDecryption(
|
||||
forSender: placeholder.sender,
|
||||
thread: thread,
|
||||
timestamp: NSDate.ows_millisecondTimeStamp(),
|
||||
transaction: writeTx)
|
||||
|
||||
placeholder.anyRemove(transaction: writeTx)
|
||||
errorMessage.anyInsert(transaction: writeTx)
|
||||
|
||||
self.notificationsManager?.notifyUser(for: errorMessage,
|
||||
thread: thread,
|
||||
transaction: writeTx)
|
||||
}
|
||||
}
|
||||
} completion: {
|
||||
self.databaseStorage.read { readTx in
|
||||
self.schedulePlaceholderCleanup(transaction: readTx)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private extension SSKProtoEnvelope {
|
||||
|
||||
@ -24,18 +24,19 @@
|
||||
{
|
||||
OWSAssertDebug(address);
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
Payload *payloadRecord = [MessageSendLog fetchPayloadWithAddress:address
|
||||
deviceId:deviceId
|
||||
timestamp:failedTimestamp
|
||||
transaction:transaction];
|
||||
|
||||
TSThread *originalThread = [TSThread anyFetchWithUniqueId:payloadRecord.uniqueThreadId transaction:transaction];
|
||||
TSThread *targetThread = [TSContactThread getOrCreateThreadWithContactAddress:address transaction:transaction];
|
||||
TSOutgoingMessageBuilder *builder = [TSOutgoingMessageBuilder outgoingMessageBuilderWithThread:targetThread];
|
||||
|
||||
Payload *_Nullable payloadRecord = [MessageSendLog fetchPayloadWithAddress:address
|
||||
deviceId:deviceId
|
||||
timestamp:failedTimestamp
|
||||
transaction:transaction];
|
||||
|
||||
TSThread *_Nullable originalThread = nil;
|
||||
if (payloadRecord) {
|
||||
OWSLogInfo(@"Found an MSL record for resend request: %lli", failedTimestamp);
|
||||
originalThread = [TSThread anyFetchWithUniqueId:payloadRecord.uniqueThreadId transaction:transaction];
|
||||
|
||||
// We should inherit the timestamp of the failed message. This allows the recipient of this message
|
||||
// to correlate the resend response with the original failed message.
|
||||
builder.timestamp = payloadRecord.sentTimestamp;
|
||||
|
||||
@ -10,7 +10,9 @@ extension OWSRecoverableDecryptionPlaceholder {
|
||||
func replaceWithInteraction(_ interaction: TSInteraction, writeTx: SDSAnyWriteTransaction) {
|
||||
Logger.info("Replacing placeholder with recovered interaction: \(interaction.timestamp)")
|
||||
guard let inheritedId = grdbId?.int64Value else { return owsFailDebug("Missing rowId") }
|
||||
|
||||
interaction.replaceRowId(inheritedId, uniqueId: uniqueId)
|
||||
interaction.replaceSortId(UInt64(inheritedId))
|
||||
|
||||
interaction.anyOverwritingUpdate(transaction: writeTx)
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSRecoverableDecryptionPlaceholderSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = model.hiddenUntilTimestamp
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,14 +16,10 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@property (assign, nonatomic, readonly) BOOL isVisible;
|
||||
@property (assign, nonatomic, readonly) BOOL supportsReplacement;
|
||||
@property (assign, nonatomic, readonly) uint64_t hiddenUntilTimestamp;
|
||||
|
||||
// Used to resolve timestamp collisions for a long-lived placeholder.
|
||||
// If a placeholder has outlived its eligible replacement period, it will live on as an error message
|
||||
// even after the replacement content has been received.
|
||||
//
|
||||
// Since we need to persist *both* the error and the replacement message, we adjust the placeholder's timestamp
|
||||
// slightly to resolve the timestamp collision.
|
||||
- (void)adjustTimestamp:(uint64_t)timestamp;
|
||||
/// After this date, the placeholder is no longer eligible for replacement with the original content.
|
||||
@property (strong, nonatomic, readonly) NSDate *expirationDate;
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
@ -31,6 +27,35 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// `sds_codegen.sh`.
|
||||
|
||||
// clang-format off
|
||||
|
||||
- (instancetype)initWithGrdbId:(int64_t)grdbId
|
||||
uniqueId:(NSString *)uniqueId
|
||||
receivedAtTimestamp:(uint64_t)receivedAtTimestamp
|
||||
sortId:(uint64_t)sortId
|
||||
timestamp:(uint64_t)timestamp
|
||||
uniqueThreadId:(NSString *)uniqueThreadId
|
||||
attachmentIds:(NSArray<NSString *> *)attachmentIds
|
||||
body:(nullable NSString *)body
|
||||
bodyRanges:(nullable MessageBodyRanges *)bodyRanges
|
||||
contactShare:(nullable OWSContact *)contactShare
|
||||
expireStartedAt:(uint64_t)expireStartedAt
|
||||
expiresAt:(uint64_t)expiresAt
|
||||
expiresInSeconds:(unsigned int)expiresInSeconds
|
||||
isViewOnceComplete:(BOOL)isViewOnceComplete
|
||||
isViewOnceMessage:(BOOL)isViewOnceMessage
|
||||
linkPreview:(nullable OWSLinkPreview *)linkPreview
|
||||
messageSticker:(nullable MessageSticker *)messageSticker
|
||||
quotedMessage:(nullable TSQuotedMessage *)quotedMessage
|
||||
storedShouldStartExpireTimer:(BOOL)storedShouldStartExpireTimer
|
||||
wasRemotelyDeleted:(BOOL)wasRemotelyDeleted
|
||||
errorType:(TSErrorMessageType)errorType
|
||||
read:(BOOL)read
|
||||
recipientAddress:(nullable SignalServiceAddress *)recipientAddress
|
||||
sender:(nullable SignalServiceAddress *)sender
|
||||
wasIdentityVerified:(BOOL)wasIdentityVerified
|
||||
hiddenUntilTimestamp:(uint64_t)hiddenUntilTimestamp
|
||||
NS_DESIGNATED_INITIALIZER NS_SWIFT_NAME(init(grdbId:uniqueId:receivedAtTimestamp:sortId:timestamp:uniqueThreadId:attachmentIds:body:bodyRanges:contactShare:expireStartedAt:expiresAt:expiresInSeconds:isViewOnceComplete:isViewOnceMessage:linkPreview:messageSticker:quotedMessage:storedShouldStartExpireTimer:wasRemotelyDeleted:errorType:read:recipientAddress:sender:wasIdentityVerified:hiddenUntilTimestamp:));
|
||||
|
||||
// clang-format on
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
@ -37,7 +37,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
builder.timestamp = envelope.timestamp;
|
||||
builder.senderAddress = sender;
|
||||
|
||||
return [super initErrorMessageWithBuilder:builder];
|
||||
self = [super initErrorMessageWithBuilder:builder];
|
||||
if (self) {
|
||||
_hiddenUntilTimestamp = [NSDate distantFutureMillisecondTimestamp];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)coder
|
||||
@ -51,40 +55,129 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// `sds_codegen.sh`.
|
||||
|
||||
// clang-format off
|
||||
|
||||
- (instancetype)initWithGrdbId:(int64_t)grdbId
|
||||
uniqueId:(NSString *)uniqueId
|
||||
receivedAtTimestamp:(uint64_t)receivedAtTimestamp
|
||||
sortId:(uint64_t)sortId
|
||||
timestamp:(uint64_t)timestamp
|
||||
uniqueThreadId:(NSString *)uniqueThreadId
|
||||
attachmentIds:(NSArray<NSString *> *)attachmentIds
|
||||
body:(nullable NSString *)body
|
||||
bodyRanges:(nullable MessageBodyRanges *)bodyRanges
|
||||
contactShare:(nullable OWSContact *)contactShare
|
||||
expireStartedAt:(uint64_t)expireStartedAt
|
||||
expiresAt:(uint64_t)expiresAt
|
||||
expiresInSeconds:(unsigned int)expiresInSeconds
|
||||
isViewOnceComplete:(BOOL)isViewOnceComplete
|
||||
isViewOnceMessage:(BOOL)isViewOnceMessage
|
||||
linkPreview:(nullable OWSLinkPreview *)linkPreview
|
||||
messageSticker:(nullable MessageSticker *)messageSticker
|
||||
quotedMessage:(nullable TSQuotedMessage *)quotedMessage
|
||||
storedShouldStartExpireTimer:(BOOL)storedShouldStartExpireTimer
|
||||
wasRemotelyDeleted:(BOOL)wasRemotelyDeleted
|
||||
errorType:(TSErrorMessageType)errorType
|
||||
read:(BOOL)read
|
||||
recipientAddress:(nullable SignalServiceAddress *)recipientAddress
|
||||
sender:(nullable SignalServiceAddress *)sender
|
||||
wasIdentityVerified:(BOOL)wasIdentityVerified
|
||||
hiddenUntilTimestamp:(uint64_t)hiddenUntilTimestamp
|
||||
{
|
||||
self = [super initWithGrdbId:grdbId
|
||||
uniqueId:uniqueId
|
||||
receivedAtTimestamp:receivedAtTimestamp
|
||||
sortId:sortId
|
||||
timestamp:timestamp
|
||||
uniqueThreadId:uniqueThreadId
|
||||
attachmentIds:attachmentIds
|
||||
body:body
|
||||
bodyRanges:bodyRanges
|
||||
contactShare:contactShare
|
||||
expireStartedAt:expireStartedAt
|
||||
expiresAt:expiresAt
|
||||
expiresInSeconds:expiresInSeconds
|
||||
isViewOnceComplete:isViewOnceComplete
|
||||
isViewOnceMessage:isViewOnceMessage
|
||||
linkPreview:linkPreview
|
||||
messageSticker:messageSticker
|
||||
quotedMessage:quotedMessage
|
||||
storedShouldStartExpireTimer:storedShouldStartExpireTimer
|
||||
wasRemotelyDeleted:wasRemotelyDeleted
|
||||
errorType:errorType
|
||||
read:read
|
||||
recipientAddress:recipientAddress
|
||||
sender:sender
|
||||
wasIdentityVerified:wasIdentityVerified];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_hiddenUntilTimestamp = hiddenUntilTimestamp;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// clang-format on
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
#pragma mark - Methods
|
||||
|
||||
- (void)adjustTimestamp:(uint64_t)timestamp
|
||||
- (NSDate *)expirationDate
|
||||
{
|
||||
OWSAssert(timestamp > 0);
|
||||
self.timestamp = timestamp;
|
||||
}
|
||||
|
||||
- (BOOL)isVisible
|
||||
{
|
||||
// If this interaction has ever been seen or the recovery period has elapsed, we should make
|
||||
// this visible to the user.
|
||||
NSTimeInterval expirationInterval = [RemoteConfig replaceableInteractionExpiration];
|
||||
OWSAssertDebug(expirationInterval >= 0);
|
||||
|
||||
NSDate *expiration = [self.receivedAtDate dateByAddingTimeInterval:MAX(0, expirationInterval)];
|
||||
return [expiration isBeforeNow] || self.wasRead;
|
||||
if (SSKDebugFlags.fastPlaceholderExpiration.value) {
|
||||
expirationInterval = MIN(expirationInterval, 5.0);
|
||||
}
|
||||
|
||||
return [self.receivedAtDate dateByAddingTimeInterval:MAX(0, expirationInterval)];
|
||||
}
|
||||
|
||||
- (BOOL)supportsReplacement
|
||||
{
|
||||
return !self.isVisible;
|
||||
return [self.expirationDate isAfterNow] && !self.wasRead;
|
||||
}
|
||||
|
||||
- (NSString *)previewTextWithTransaction:(SDSAnyReadTransaction *)transaction
|
||||
{
|
||||
NSString *formatString = NSLocalizedString(
|
||||
@"ERROR_MESSAGE_DECRYPTION_FAILURE", @"Error message for a decryption failure. Embeds {{sender short name}}.");
|
||||
NSString *senderName = [self.contactsManager shortDisplayNameForAddress:self.sender transaction:transaction];
|
||||
return [[NSString alloc] initWithFormat:formatString, senderName];
|
||||
NSString *_Nullable senderName = nil;
|
||||
if (self.sender) {
|
||||
senderName = [self.contactsManager shortDisplayNameForAddress:self.sender transaction:transaction];
|
||||
}
|
||||
|
||||
if (SSKDebugFlags.showFailedDecryptionPlaceholders.value) {
|
||||
return [[NSString alloc]
|
||||
initWithFormat:@"Placeholder for timestamp: %llu from sender: %@", self.timestamp, senderName];
|
||||
} else if (senderName) {
|
||||
OWSFailDebug(@"Should not be directly surfaced to user");
|
||||
NSString *formatString = NSLocalizedString(@"ERROR_MESSAGE_DECRYPTION_FAILURE",
|
||||
@"Error message for a decryption failure. Embeds {{sender short name}}.");
|
||||
return [[NSString alloc] initWithFormat:formatString, senderName];
|
||||
} else {
|
||||
OWSFailDebug(@"Should not be directly surfaced to user");
|
||||
return NSLocalizedString(
|
||||
@"ERROR_MESSAGE_DECRYPTION_FAILURE_UNKNOWN_SENDER", @"Error message for a decryption failure.");
|
||||
}
|
||||
}
|
||||
|
||||
- (void)anyDidInsertWithTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
[super anyDidInsertWithTransaction:transaction];
|
||||
[self.messageDecrypter schedulePlaceholderCleanupWithTransaction:transaction];
|
||||
}
|
||||
|
||||
#pragma mark - <OWSReadTracking>
|
||||
|
||||
- (void)markAsReadAtTimestamp:(uint64_t)readTimestamp
|
||||
thread:(TSThread *)thread
|
||||
circumstance:(OWSReceiptCircumstance)circumstance
|
||||
transaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
OWSLogInfo(@"Marking placeholder as read. No longer eligible for inline replacement.");
|
||||
[super markAsReadAtTimestamp:readTimestamp thread:thread circumstance:circumstance transaction:transaction];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSUnknownContactBlockOfferMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSUnknownProtocolVersionMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class OWSOutgoingPaymentMessageSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = optionalArchive(model.paymentRequest)
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +125,8 @@ class TSCallSerializer: SDSSerializer {
|
||||
let paymentRequest: Data? = nil
|
||||
let viewed: Bool? = nil
|
||||
let serverGuid: String? = nil
|
||||
let hiddenUntilTimestamp: UInt64? = nil
|
||||
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid)
|
||||
return InteractionRecord(delegate: model, id: id, recordType: recordType, uniqueId: uniqueId, receivedAtTimestamp: receivedAtTimestamp, timestamp: timestamp, threadUniqueId: threadUniqueId, attachmentIds: attachmentIds, authorId: authorId, authorPhoneNumber: authorPhoneNumber, authorUUID: authorUUID, body: body, callType: callType, configurationDurationSeconds: configurationDurationSeconds, configurationIsEnabled: configurationIsEnabled, contactShare: contactShare, createdByRemoteName: createdByRemoteName, createdInExistingGroup: createdInExistingGroup, customMessage: customMessage, envelopeData: envelopeData, errorType: errorType, expireStartedAt: expireStartedAt, expiresAt: expiresAt, expiresInSeconds: expiresInSeconds, groupMetaMessage: groupMetaMessage, hasLegacyMessageState: hasLegacyMessageState, hasSyncedTranscript: hasSyncedTranscript, isFromLinkedDevice: isFromLinkedDevice, isLocalChange: isLocalChange, isViewOnceComplete: isViewOnceComplete, isViewOnceMessage: isViewOnceMessage, isVoiceMessage: isVoiceMessage, legacyMessageState: legacyMessageState, legacyWasDelivered: legacyWasDelivered, linkPreview: linkPreview, messageId: messageId, messageSticker: messageSticker, messageType: messageType, mostRecentFailureText: mostRecentFailureText, preKeyBundle: preKeyBundle, protocolVersion: protocolVersion, quotedMessage: quotedMessage, read: read, recipientAddress: recipientAddress, recipientAddressStates: recipientAddressStates, sender: sender, serverTimestamp: serverTimestamp, sourceDeviceId: sourceDeviceId, storedMessageState: storedMessageState, storedShouldStartExpireTimer: storedShouldStartExpireTimer, unregisteredAddress: unregisteredAddress, verificationState: verificationState, wasReceivedByUD: wasReceivedByUD, infoMessageUserInfo: infoMessageUserInfo, wasRemotelyDeleted: wasRemotelyDeleted, bodyRanges: bodyRanges, offerType: offerType, serverDeliveryTimestamp: serverDeliveryTimestamp, eraId: eraId, hasEnded: hasEnded, creatorUuid: creatorUuid, joinedMemberUuids: joinedMemberUuids, wasIdentityVerified: wasIdentityVerified, paymentCancellation: paymentCancellation, paymentNotification: paymentNotification, paymentRequest: paymentRequest, viewed: viewed, serverGuid: serverGuid, hiddenUntilTimestamp: hiddenUntilTimestamp)
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,6 +111,7 @@ public class GRDBSchemaMigrator: NSObject {
|
||||
case addSendCompletionToMessageSendLog
|
||||
case addExclusiveProcessIdentifierAndHighPriorityToJobRecord
|
||||
case updateMessageSendLogColumnTypes
|
||||
case addHiddenInteractionColumn
|
||||
|
||||
// NOTE: Every time we add a migration id, consider
|
||||
// incrementing grdbSchemaVersionLatest.
|
||||
@ -1398,6 +1399,16 @@ public class GRDBSchemaMigrator: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
migrator.registerMigration(MigrationId.addHiddenInteractionColumn.rawValue) { db in
|
||||
do {
|
||||
try db.alter(table: "model_TSInteraction") { (table: TableAlteration) -> Void in
|
||||
table.add(column: "hiddenUntilTimestamp", .integer)
|
||||
}
|
||||
} catch {
|
||||
owsFail("Error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Schema Migration Insertion Point
|
||||
}
|
||||
|
||||
|
||||
@ -39,12 +39,12 @@ protocol InteractionFinderAdapter {
|
||||
|
||||
func earliestKnownInteractionRowId(transaction: ReadTransaction) -> Int?
|
||||
|
||||
func distanceFromLatest(interactionUniqueId: String, transaction: ReadTransaction) throws -> UInt?
|
||||
func count(transaction: ReadTransaction) -> UInt
|
||||
func distanceFromLatest(interactionUniqueId: String, includingHiddenInteractions countHidden: Bool, transaction: ReadTransaction) throws -> UInt?
|
||||
func count(includingHiddenInteractions: Bool, transaction: ReadTransaction) -> UInt
|
||||
func enumerateInteractionIds(transaction: ReadTransaction, block: @escaping (String, UnsafeMutablePointer<ObjCBool>) throws -> Void) throws
|
||||
func enumerateRecentInteractions(transaction: ReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer<ObjCBool>) -> Void) throws
|
||||
func enumerateInteractions(range: NSRange, transaction: ReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer<ObjCBool>) -> Void) throws
|
||||
func interactionIds(inRange range: NSRange, transaction: ReadTransaction) throws -> [String]
|
||||
func enumerateInteractions(range: NSRange, includingHiddenInteractions: Bool, transaction: ReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer<ObjCBool>) -> Void) throws
|
||||
func interactionIds(inRange range: NSRange, includingHiddenInteractions: Bool, transaction: ReadTransaction) throws -> [String]
|
||||
func existsOutgoingMessage(transaction: ReadTransaction) -> Bool
|
||||
func outgoingMessageCount(transaction: ReadTransaction) -> UInt
|
||||
|
||||
@ -287,20 +287,20 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
public func distanceFromLatest(interactionUniqueId: String, transaction: SDSAnyReadTransaction) throws -> UInt? {
|
||||
public func distanceFromLatest(interactionUniqueId: String, includingHiddenInteractions countHidden: Bool = true, transaction: SDSAnyReadTransaction) throws -> UInt? {
|
||||
return try Bench(title: "InteractionFinder.distanceFromLatest") {
|
||||
switch transaction.readTransaction {
|
||||
case .grdbRead(let grdbRead):
|
||||
return try grdbAdapter.distanceFromLatest(interactionUniqueId: interactionUniqueId, transaction: grdbRead)
|
||||
return try grdbAdapter.distanceFromLatest(interactionUniqueId: interactionUniqueId, includingHiddenInteractions: countHidden, transaction: grdbRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
public func count(transaction: SDSAnyReadTransaction) -> UInt {
|
||||
public func count(includingHiddenInteractions includeHidden: Bool = true, transaction: SDSAnyReadTransaction) -> UInt {
|
||||
switch transaction.readTransaction {
|
||||
case .grdbRead(let grdbRead):
|
||||
return grdbAdapter.count(transaction: grdbRead)
|
||||
return grdbAdapter.count(includingHiddenInteractions: includeHidden, transaction: grdbRead)
|
||||
}
|
||||
}
|
||||
|
||||
@ -351,17 +351,17 @@ public class InteractionFinder: NSObject, InteractionFinderAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
public func enumerateInteractions(range: NSRange, transaction: SDSAnyReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
|
||||
public func enumerateInteractions(range: NSRange, includingHiddenInteractions includeHidden: Bool = true, transaction: SDSAnyReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
|
||||
switch transaction.readTransaction {
|
||||
case .grdbRead(let grdbRead):
|
||||
return try grdbAdapter.enumerateInteractions(range: range, transaction: grdbRead, block: block)
|
||||
return try grdbAdapter.enumerateInteractions(range: range, includingHiddenInteractions: includeHidden, transaction: grdbRead, block: block)
|
||||
}
|
||||
}
|
||||
|
||||
public func interactionIds(inRange range: NSRange, transaction: SDSAnyReadTransaction) throws -> [String] {
|
||||
public func interactionIds(inRange range: NSRange, includingHiddenInteractions includeHidden: Bool = true, transaction: SDSAnyReadTransaction) throws -> [String] {
|
||||
switch transaction.readTransaction {
|
||||
case .grdbRead(let grdbRead):
|
||||
return try grdbAdapter.interactionIds(inRange: range, transaction: grdbRead)
|
||||
return try grdbAdapter.interactionIds(inRange: range, includingHiddenInteractions: includeHidden, transaction: grdbRead)
|
||||
}
|
||||
}
|
||||
|
||||
@ -849,6 +849,50 @@ public class GRDBInteractionFinder: NSObject, InteractionFinderAdapter {
|
||||
return interactions
|
||||
}
|
||||
|
||||
static func oldestPlaceholderInteraction(transaction: GRDBReadTransaction) -> OWSRecoverableDecryptionPlaceholder? {
|
||||
let sql = """
|
||||
SELECT *
|
||||
FROM \(InteractionRecord.databaseTableName)
|
||||
WHERE \(interactionColumn: .recordType) IS \(SDSRecordType.recoverableDecryptionPlaceholder.rawValue)
|
||||
ORDER BY \(interactionColumn: .id) ASC
|
||||
LIMIT 1
|
||||
"""
|
||||
let result = TSInteraction.grdbFetchOne(sql: sql, transaction: transaction)
|
||||
if let result = result as? OWSRecoverableDecryptionPlaceholder {
|
||||
return result
|
||||
} else if let result = result {
|
||||
owsFailDebug("Unexpected type: \(type(of: result))")
|
||||
return nil
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static func enumeratePlaceholders(transaction: GRDBReadTransaction, block: (OWSRecoverableDecryptionPlaceholder, UnsafeMutablePointer<ObjCBool>) -> Void) {
|
||||
let sql = """
|
||||
SELECT *
|
||||
FROM \(InteractionRecord.databaseTableName)
|
||||
WHERE \(interactionColumn: .recordType) IS \(SDSRecordType.recoverableDecryptionPlaceholder.rawValue)
|
||||
ORDER BY \(interactionColumn: .id) ASC
|
||||
"""
|
||||
do {
|
||||
let cursor = TSInteraction.grdbFetchCursor(sql: sql, transaction: transaction)
|
||||
while let result = try cursor.next() {
|
||||
if let placeholder = result as? OWSRecoverableDecryptionPlaceholder {
|
||||
var stop: ObjCBool = false
|
||||
block(placeholder, &stop)
|
||||
if stop.boolValue {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
owsFailDebug("Unexpected type: \(type(of: result))")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
owsFailDebug("unexpected error \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - instance methods
|
||||
|
||||
public func profileUpdateInteractions(afterSortId sortId: UInt64, transaction: GRDBReadTransaction) -> [TSInfoMessage] {
|
||||
@ -965,11 +1009,14 @@ public class GRDBInteractionFinder: NSObject, InteractionFinderAdapter {
|
||||
return try? Int.fetchOne(transaction.database, sql: sql, arguments: arguments)
|
||||
}
|
||||
|
||||
func distanceFromLatest(interactionUniqueId: String, transaction: GRDBReadTransaction) throws -> UInt? {
|
||||
func distanceFromLatest(interactionUniqueId: String, includingHiddenInteractions countHidden: Bool = true, transaction: GRDBReadTransaction) throws -> UInt? {
|
||||
let hiddenInteractionFilterClause = "AND (\(interactionColumn: .hiddenUntilTimestamp) < \(Date().ows_millisecondsSince1970) OR \(interactionColumn: .hiddenUntilTimestamp) IS NULL)"
|
||||
|
||||
guard let interactionId = try UInt.fetchOne(transaction.database, sql: """
|
||||
SELECT id
|
||||
FROM \(InteractionRecord.databaseTableName)
|
||||
WHERE \(interactionColumn: .uniqueId) = ?
|
||||
\(countHidden ? "" : hiddenInteractionFilterClause)
|
||||
""", arguments: [interactionUniqueId]) else {
|
||||
owsFailDebug("failed to find id for interaction \(interactionUniqueId)")
|
||||
return nil
|
||||
@ -980,6 +1027,7 @@ public class GRDBInteractionFinder: NSObject, InteractionFinderAdapter {
|
||||
FROM \(InteractionRecord.databaseTableName)
|
||||
WHERE \(interactionColumn: .threadUniqueId) = ?
|
||||
AND \(interactionColumn: .id) >= ?
|
||||
\(countHidden ? "" : hiddenInteractionFilterClause)
|
||||
ORDER BY \(interactionColumn: .id) DESC
|
||||
""", arguments: [threadUniqueId, interactionId]) else {
|
||||
owsFailDebug("failed to find distance from latest message")
|
||||
@ -989,13 +1037,15 @@ public class GRDBInteractionFinder: NSObject, InteractionFinderAdapter {
|
||||
return distanceFromLatest
|
||||
}
|
||||
|
||||
func count(transaction: GRDBReadTransaction) -> UInt {
|
||||
func count(includingHiddenInteractions includeHidden: Bool = true, transaction: GRDBReadTransaction) -> UInt {
|
||||
do {
|
||||
let hiddenInteractionFilterClause = "AND (\(interactionColumn: .hiddenUntilTimestamp) < \(Date().ows_millisecondsSince1970) OR \(interactionColumn: .hiddenUntilTimestamp) IS NULL)"
|
||||
guard let count = try UInt.fetchOne(transaction.database,
|
||||
sql: """
|
||||
SELECT COUNT(*)
|
||||
FROM \(InteractionRecord.databaseTableName)
|
||||
WHERE \(interactionColumn: .threadUniqueId) = ?
|
||||
\(includeHidden ? "" : hiddenInteractionFilterClause)
|
||||
""",
|
||||
arguments: [threadUniqueId]) else {
|
||||
throw OWSAssertionError("count was unexpectedly nil")
|
||||
@ -1046,11 +1096,13 @@ public class GRDBInteractionFinder: NSObject, InteractionFinderAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
func enumerateInteractions(range: NSRange, transaction: GRDBReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
|
||||
func enumerateInteractions(range: NSRange, includingHiddenInteractions includeHidden: Bool = true, transaction: GRDBReadTransaction, block: @escaping (TSInteraction, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
|
||||
let hiddenInteractionFilterClause = "AND (\(interactionColumn: .hiddenUntilTimestamp) < \(Date().ows_millisecondsSince1970) OR \(interactionColumn: .hiddenUntilTimestamp) IS NULL)"
|
||||
let sql = """
|
||||
SELECT *
|
||||
FROM \(InteractionRecord.databaseTableName)
|
||||
WHERE \(interactionColumn: .threadUniqueId) = ?
|
||||
\(includeHidden ? "" : hiddenInteractionFilterClause)
|
||||
ORDER BY \(interactionColumn: .id)
|
||||
LIMIT \(range.length)
|
||||
OFFSET \(range.location)
|
||||
@ -1069,11 +1121,14 @@ public class GRDBInteractionFinder: NSObject, InteractionFinderAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
func interactionIds(inRange range: NSRange, transaction: GRDBReadTransaction) throws -> [String] {
|
||||
func interactionIds(inRange range: NSRange, includingHiddenInteractions includeHidden: Bool = true, transaction: GRDBReadTransaction) throws -> [String] {
|
||||
let hiddenInteractionFilterClause = "AND (\(interactionColumn: .hiddenUntilTimestamp) < \(Date().ows_millisecondsSince1970) OR \(interactionColumn: .hiddenUntilTimestamp) IS NULL)"
|
||||
|
||||
let sql = """
|
||||
SELECT \(interactionColumn: .uniqueId)
|
||||
FROM \(InteractionRecord.databaseTableName)
|
||||
WHERE \(interactionColumn: .threadUniqueId) = ?
|
||||
\(includeHidden ? "" : hiddenInteractionFilterClause)
|
||||
ORDER BY \(interactionColumn: .id)
|
||||
LIMIT \(range.length)
|
||||
OFFSET \(range.location)
|
||||
|
||||
@ -32,6 +32,14 @@ public extension NSDate {
|
||||
var ows_millisecondsSince1970: UInt64 {
|
||||
return NSDate.ows_millisecondsSince1970(for: self as Date)
|
||||
}
|
||||
|
||||
static var distantFutureForMillisecondTimestamp: Date {
|
||||
Date.distantFutureForMillisecondTimestamp
|
||||
}
|
||||
|
||||
static var distantFutureMillisecondTimestamp: UInt64 {
|
||||
Date.distantFutureMillisecondTimestamp
|
||||
}
|
||||
}
|
||||
|
||||
public extension Date {
|
||||
@ -63,6 +71,10 @@ public extension Date {
|
||||
return result
|
||||
}
|
||||
|
||||
static var distantFutureMillisecondTimestamp: UInt64 {
|
||||
distantFutureForMillisecondTimestamp.ows_millisecondsSince1970
|
||||
}
|
||||
|
||||
func isBefore(_ date: Date) -> Bool {
|
||||
(self as NSDate).is(before: date)
|
||||
}
|
||||
|
||||
@ -501,9 +501,22 @@ public class DebugFlags: BaseFlags {
|
||||
|
||||
@objc
|
||||
public static let delayedMessageResend = TestableFlag(false,
|
||||
title: LocalizationNotNeeded("Delayed message resend"),
|
||||
title: LocalizationNotNeeded("Sender Key: Delayed message resend"),
|
||||
details: LocalizationNotNeeded("Waits 10s before responding to a resend request."))
|
||||
|
||||
@objc
|
||||
public static let showFailedDecryptionPlaceholders = TestableFlag(false,
|
||||
title: LocalizationNotNeeded("Sender Key: Show failed decryption placeholders"),
|
||||
details: LocalizationNotNeeded("Shows placeholder interactions in the conversation list."))
|
||||
|
||||
@objc
|
||||
public static let fastPlaceholderExpiration = TestableFlag(false,
|
||||
title: LocalizationNotNeeded("Sender Key: Early placeholder expiration"),
|
||||
details: LocalizationNotNeeded("Shortens the valid window for message resend+recovery."),
|
||||
toggleHandler: { _ in
|
||||
databaseStorage.read { messageDecrypter.schedulePlaceholderCleanup(transaction: $0)}
|
||||
})
|
||||
|
||||
public static func buildFlagMap() -> [String: Any] {
|
||||
BaseFlags.buildFlagMap(for: DebugFlags.self) { (key: String) -> Any? in
|
||||
DebugFlags.value(forKey: key)
|
||||
@ -586,16 +599,19 @@ public class TestableFlag: NSObject {
|
||||
private let flag: AtomicBool
|
||||
public let title: String
|
||||
public let details: String
|
||||
public let toggleHandler: ((Bool) -> Void)?
|
||||
|
||||
fileprivate init(_ defaultValue: Bool,
|
||||
title: String,
|
||||
details: String,
|
||||
affectsCapabilities: Bool = false) {
|
||||
affectsCapabilities: Bool = false,
|
||||
toggleHandler: ((Bool) -> Void)? = nil) {
|
||||
self.defaultValue = defaultValue
|
||||
self.title = title
|
||||
self.details = details
|
||||
self.affectsCapabilities = affectsCapabilities
|
||||
self.flag = AtomicBool(defaultValue)
|
||||
self.toggleHandler = toggleHandler
|
||||
|
||||
super.init()
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user