mirror of https://github.com/oxen-io/session-ios
				
				
				
			
							parent
							
								
									289291e03d
								
							
						
					
					
						commit
						ffe44e68be
					
				@ -0,0 +1,21 @@
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "TSYapDatabaseObject.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
@interface OWSLinkedDeviceReadReceipt : TSYapDatabaseObject
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, readonly) NSString *senderId;
 | 
			
		||||
@property (nonatomic, readonly) uint64_t timestamp;
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithSenderId:(NSString *)senderId timestamp:(uint64_t)timestamp;
 | 
			
		||||
 | 
			
		||||
+ (nullable OWSLinkedDeviceReadReceipt *)linkedDeviceReadReceiptWithSenderId:(NSString *)senderId
 | 
			
		||||
                                                                   timestamp:(uint64_t)timestamp;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@ -0,0 +1,53 @@
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "OWSLinkedDeviceReadReceipt.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
@implementation OWSLinkedDeviceReadReceipt
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithSenderId:(NSString *)senderId timestamp:(uint64_t)timestamp;
 | 
			
		||||
{
 | 
			
		||||
    OWSAssert(senderId.length > 0 && timestamp > 0);
 | 
			
		||||
 | 
			
		||||
    self = [super initWithUniqueId:[OWSLinkedDeviceReadReceipt uniqueIdForSenderId:senderId timestamp:timestamp]];
 | 
			
		||||
    if (!self) {
 | 
			
		||||
        return self;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _senderId = senderId;
 | 
			
		||||
    _timestamp = timestamp;
 | 
			
		||||
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
+ (NSString *)uniqueIdForSenderId:(NSString *)senderId timestamp:(uint64_t)timestamp
 | 
			
		||||
{
 | 
			
		||||
    OWSAssert(senderId.length > 0 && timestamp > 0);
 | 
			
		||||
 | 
			
		||||
    return [NSString stringWithFormat:@"%@ %llu", senderId, timestamp];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
+ (nullable OWSLinkedDeviceReadReceipt *)linkedDeviceReadReceiptWithSenderId:(NSString *)senderId
 | 
			
		||||
                                                                   timestamp:(uint64_t)timestamp
 | 
			
		||||
{
 | 
			
		||||
    return [OWSLinkedDeviceReadReceipt fetchObjectWithUniqueID:[self uniqueIdForSenderId:senderId timestamp:timestamp]];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - Logging
 | 
			
		||||
 | 
			
		||||
+ (NSString *)tag
 | 
			
		||||
{
 | 
			
		||||
    return [NSString stringWithFormat:@"[%@]", self.class];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)tag
 | 
			
		||||
{
 | 
			
		||||
    return self.class.tag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@ -1,23 +0,0 @@
 | 
			
		||||
//  Copyright © 2016 Open Whisper Systems. All rights reserved.
 | 
			
		||||
 | 
			
		||||
#import "TSYapDatabaseObject.h"
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
@class YapDatabase;
 | 
			
		||||
 | 
			
		||||
@interface OWSReadReceipt : TSYapDatabaseObject
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, readonly) NSString *senderId;
 | 
			
		||||
@property (nonatomic, readonly) uint64_t timestamp;
 | 
			
		||||
@property (nonatomic, readonly, getter=isValid) BOOL valid;
 | 
			
		||||
@property (nonatomic, readonly) NSArray<NSString *> *validationErrorMessages;
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithSenderId:(NSString *)senderId timestamp:(uint64_t)timestamp;
 | 
			
		||||
 | 
			
		||||
+ (nullable instancetype)firstWithSenderId:(NSString *)senderId timestamp:(uint64_t)timestamp;
 | 
			
		||||
+ (void)asyncRegisterIndexOnSenderIdAndTimestampWithDatabase:(YapDatabase *)database;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@ -1,140 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "OWSReadReceipt.h"
 | 
			
		||||
#import <YapDatabase/YapDatabase.h>
 | 
			
		||||
#import <YapDatabase/YapDatabaseConnection.h>
 | 
			
		||||
#import <YapDatabase/YapDatabaseSecondaryIndex.h>
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
NSString *const OWSReadReceiptIndexOnSenderIdAndTimestamp = @"OWSReadReceiptIndexOnSenderIdAndTimestamp";
 | 
			
		||||
NSString *const OWSReadReceiptColumnTimestamp = @"timestamp";
 | 
			
		||||
NSString *const OWSReadReceiptColumnSenderId = @"senderId";
 | 
			
		||||
 | 
			
		||||
@implementation OWSReadReceipt
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithSenderId:(NSString *)senderId timestamp:(uint64_t)timestamp;
 | 
			
		||||
{
 | 
			
		||||
    self = [super init];
 | 
			
		||||
    if (!self) {
 | 
			
		||||
        return self;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    NSMutableArray<NSString *> *validationErrorMessage = [NSMutableArray new];
 | 
			
		||||
    if (!senderId) {
 | 
			
		||||
        [validationErrorMessage addObject:@"Must specify sender id"];
 | 
			
		||||
    }
 | 
			
		||||
    _senderId = senderId;
 | 
			
		||||
 | 
			
		||||
    if (!timestamp) {
 | 
			
		||||
        [validationErrorMessage addObject:@"Must specify timestamp"];
 | 
			
		||||
    }
 | 
			
		||||
    _timestamp = timestamp;
 | 
			
		||||
 | 
			
		||||
    _valid = validationErrorMessage.count == 0;
 | 
			
		||||
    _validationErrorMessages = [validationErrorMessage copy];
 | 
			
		||||
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithCoder:(NSCoder *)decoder
 | 
			
		||||
{
 | 
			
		||||
    self = [super initWithCoder:decoder];
 | 
			
		||||
    if (!self) {
 | 
			
		||||
        return nil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _valid = YES;
 | 
			
		||||
    _validationErrorMessages = @[];
 | 
			
		||||
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
+ (MTLPropertyStorage)storageBehaviorForPropertyWithKey:(NSString *)propertyKey
 | 
			
		||||
{
 | 
			
		||||
    // Don't store ephemeral properties.
 | 
			
		||||
    if ([propertyKey isEqualToString:@"valid"] || [propertyKey isEqualToString:@"validationErrorMessages"]) {
 | 
			
		||||
        return MTLPropertyStorageNone;
 | 
			
		||||
    } else {
 | 
			
		||||
        return [super storageBehaviorForPropertyWithKey:propertyKey];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
+ (void)asyncRegisterIndexOnSenderIdAndTimestampWithDatabase:(YapDatabase *)database
 | 
			
		||||
{
 | 
			
		||||
    YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new];
 | 
			
		||||
    [setup addColumn:OWSReadReceiptColumnSenderId withType:YapDatabaseSecondaryIndexTypeText];
 | 
			
		||||
    [setup addColumn:OWSReadReceiptColumnTimestamp withType:YapDatabaseSecondaryIndexTypeInteger];
 | 
			
		||||
 | 
			
		||||
    YapDatabaseSecondaryIndexHandler *handler =
 | 
			
		||||
        [YapDatabaseSecondaryIndexHandler withObjectBlock:^(YapDatabaseReadTransaction *transaction,
 | 
			
		||||
            NSMutableDictionary *dict,
 | 
			
		||||
            NSString *collection,
 | 
			
		||||
            NSString *key,
 | 
			
		||||
            id object) {
 | 
			
		||||
            if ([object isKindOfClass:[OWSReadReceipt class]]) {
 | 
			
		||||
                OWSReadReceipt *readReceipt = (OWSReadReceipt *)object;
 | 
			
		||||
                dict[OWSReadReceiptColumnSenderId] = readReceipt.senderId;
 | 
			
		||||
                dict[OWSReadReceiptColumnTimestamp] = @(readReceipt.timestamp);
 | 
			
		||||
            }
 | 
			
		||||
        }];
 | 
			
		||||
 | 
			
		||||
    YapDatabaseSecondaryIndex *index = [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler];
 | 
			
		||||
 | 
			
		||||
    [database
 | 
			
		||||
        asyncRegisterExtension:index
 | 
			
		||||
                      withName:OWSReadReceiptIndexOnSenderIdAndTimestamp
 | 
			
		||||
               completionBlock:^(BOOL ready) {
 | 
			
		||||
                   if (ready) {
 | 
			
		||||
                       DDLogDebug(@"%@ Successfully set up extension: %@",
 | 
			
		||||
                           self.tag,
 | 
			
		||||
                           OWSReadReceiptIndexOnSenderIdAndTimestamp);
 | 
			
		||||
                   } else {
 | 
			
		||||
                       DDLogError(
 | 
			
		||||
                           @"%@ Unable to setup extension: %@", self.tag, OWSReadReceiptIndexOnSenderIdAndTimestamp);
 | 
			
		||||
                   }
 | 
			
		||||
               }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
+ (nullable instancetype)firstWithSenderId:(NSString *)senderId timestamp:(uint64_t)timestamp
 | 
			
		||||
{
 | 
			
		||||
    __block OWSReadReceipt *foundReadReceipt;
 | 
			
		||||
 | 
			
		||||
    NSString *queryFormat = [NSString
 | 
			
		||||
        stringWithFormat:@"WHERE %@ = ? AND %@ = ?", OWSReadReceiptColumnSenderId, OWSReadReceiptColumnTimestamp];
 | 
			
		||||
    YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:queryFormat, senderId, @(timestamp)];
 | 
			
		||||
 | 
			
		||||
    [[self dbReadConnection] readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
 | 
			
		||||
        [[transaction ext:OWSReadReceiptIndexOnSenderIdAndTimestamp]
 | 
			
		||||
            enumerateKeysAndObjectsMatchingQuery:query
 | 
			
		||||
                                      usingBlock:^(NSString *collection, NSString *key, id object, BOOL *stop) {
 | 
			
		||||
                                          if (![object isKindOfClass:[OWSReadReceipt class]]) {
 | 
			
		||||
                                              DDLogError(@"%@ Unexpected object in index: %@", self.tag, object);
 | 
			
		||||
                                              return;
 | 
			
		||||
                                          }
 | 
			
		||||
 | 
			
		||||
                                          foundReadReceipt = (OWSReadReceipt *)object;
 | 
			
		||||
                                          *stop = YES;
 | 
			
		||||
                                      }];
 | 
			
		||||
    }];
 | 
			
		||||
 | 
			
		||||
    return foundReadReceipt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma mark - Logging
 | 
			
		||||
 | 
			
		||||
+ (NSString *)tag
 | 
			
		||||
{
 | 
			
		||||
    return [NSString stringWithFormat:@"[%@]", self.class];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)tag
 | 
			
		||||
{
 | 
			
		||||
    return self.class.tag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@ -1,41 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
@class OWSReadReceipt;
 | 
			
		||||
@class OWSSignalServiceProtosSyncMessageRead;
 | 
			
		||||
@class TSIncomingMessage;
 | 
			
		||||
@class TSStorageManager;
 | 
			
		||||
@class YapDatabaseReadWriteTransaction;
 | 
			
		||||
 | 
			
		||||
extern NSString *const OWSReadReceiptsProcessorMarkedMessageAsReadNotification;
 | 
			
		||||
 | 
			
		||||
// TODO:
 | 
			
		||||
@interface OWSReadReceiptsProcessor : NSObject
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mark existing messages as read from the given received read receipts.
 | 
			
		||||
 */
 | 
			
		||||
- (instancetype)initWithReadReceiptProtos:(NSArray<OWSSignalServiceProtosSyncMessageRead *> *)readReceiptProtos
 | 
			
		||||
                           storageManager:(TSStorageManager *)storageManager;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mark a new message as read in the rare (but does happen!) case that we receive the read receipt before the message
 | 
			
		||||
 * the read receipt refers to.
 | 
			
		||||
 */
 | 
			
		||||
- (instancetype)initWithIncomingMessage:(TSIncomingMessage *)incomingMessage
 | 
			
		||||
                         storageManager:(TSStorageManager *)storageManager;
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithReadReceipts:(NSArray<OWSReadReceipt *> *)readReceipts
 | 
			
		||||
                      storageManager:(TSStorageManager *)storageManager NS_DESIGNATED_INITIALIZER;
 | 
			
		||||
 | 
			
		||||
- (instancetype)init NS_UNAVAILABLE;
 | 
			
		||||
 | 
			
		||||
- (void)process;
 | 
			
		||||
- (void)processWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
@ -1,162 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#import "OWSReadReceiptsProcessor.h"
 | 
			
		||||
#import "NSNotificationCenter+OWS.h"
 | 
			
		||||
#import "OWSDisappearingMessagesJob.h"
 | 
			
		||||
#import "OWSReadReceipt.h"
 | 
			
		||||
#import "OWSSignalServiceProtos.pb.h"
 | 
			
		||||
#import "TSContactThread.h"
 | 
			
		||||
#import "TSDatabaseView.h"
 | 
			
		||||
#import "TSIncomingMessage.h"
 | 
			
		||||
#import "TSStorageManager.h"
 | 
			
		||||
#import <YapDatabase/YapDatabaseConnection.h>
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_BEGIN
 | 
			
		||||
 | 
			
		||||
NSString *const OWSReadReceiptsProcessorMarkedMessageAsReadNotification =
 | 
			
		||||
    @"OWSReadReceiptsProcessorMarkedMessageAsReadNotification";
 | 
			
		||||
 | 
			
		||||
@interface OWSReadReceiptsProcessor ()
 | 
			
		||||
 | 
			
		||||
@property (nonatomic, readonly) NSArray<OWSReadReceipt *> *readReceipts;
 | 
			
		||||
@property (nonatomic, readonly) TSStorageManager *storageManager;
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@implementation OWSReadReceiptsProcessor
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithReadReceipts:(NSArray<OWSReadReceipt *> *)readReceipts
 | 
			
		||||
                      storageManager:(TSStorageManager *)storageManager;
 | 
			
		||||
{
 | 
			
		||||
    self = [super init];
 | 
			
		||||
    if (!self) {
 | 
			
		||||
        return self;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _readReceipts = [readReceipts copy];
 | 
			
		||||
    _storageManager = storageManager;
 | 
			
		||||
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithReadReceiptProtos:(NSArray<OWSSignalServiceProtosSyncMessageRead *> *)readReceiptProtos
 | 
			
		||||
                           storageManager:(TSStorageManager *)storageManager
 | 
			
		||||
{
 | 
			
		||||
    NSMutableArray<OWSReadReceipt *> *readReceipts = [NSMutableArray new];
 | 
			
		||||
    for (OWSSignalServiceProtosSyncMessageRead *readReceiptProto in readReceiptProtos) {
 | 
			
		||||
        OWSReadReceipt *readReceipt =
 | 
			
		||||
            [[OWSReadReceipt alloc] initWithSenderId:readReceiptProto.sender timestamp:readReceiptProto.timestamp];
 | 
			
		||||
        if (readReceipt.isValid) {
 | 
			
		||||
            [readReceipts addObject:readReceipt];
 | 
			
		||||
        } else {
 | 
			
		||||
            DDLogError(@"%@ Received invalid read receipt: %@", self.tag, readReceipt.validationErrorMessages);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return [self initWithReadReceipts:[readReceipts copy] storageManager:storageManager];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (instancetype)initWithIncomingMessage:(TSIncomingMessage *)message storageManager:(TSStorageManager *)storageManager
 | 
			
		||||
{
 | 
			
		||||
    NSString *messageAuthorId = message.messageAuthorId;
 | 
			
		||||
    OWSAssert(messageAuthorId.length > 0);
 | 
			
		||||
 | 
			
		||||
    OWSReadReceipt *readReceipt = [OWSReadReceipt firstWithSenderId:messageAuthorId timestamp:message.timestamp];
 | 
			
		||||
    if (readReceipt) {
 | 
			
		||||
        DDLogInfo(@"%@ Found prior read receipt for incoming message.", self.tag);
 | 
			
		||||
        return [self initWithReadReceipts:@[ readReceipt ] storageManager:storageManager];
 | 
			
		||||
    } else {
 | 
			
		||||
        // no-op
 | 
			
		||||
        return [self initWithReadReceipts:@[] storageManager:storageManager];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)process
 | 
			
		||||
{
 | 
			
		||||
    [[self.storageManager newDatabaseConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
 | 
			
		||||
        [self processWithTransaction:transaction];
 | 
			
		||||
    }];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)processWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
 | 
			
		||||
{
 | 
			
		||||
    OWSAssert(transaction);
 | 
			
		||||
 | 
			
		||||
    DDLogDebug(@"%@ Processing %ld read receipts.", self.tag, (unsigned long)self.readReceipts.count);
 | 
			
		||||
    for (OWSReadReceipt *readReceipt in self.readReceipts) {
 | 
			
		||||
        TSIncomingMessage *message = [TSIncomingMessage findMessageWithAuthorId:readReceipt.senderId
 | 
			
		||||
                                                                      timestamp:readReceipt.timestamp
 | 
			
		||||
                                                                    transaction:transaction];
 | 
			
		||||
        if (message) {
 | 
			
		||||
            OWSAssert(message.thread);
 | 
			
		||||
 | 
			
		||||
            // Mark all unread messages in this thread that are older than message specified in the read
 | 
			
		||||
            // receipt.
 | 
			
		||||
            NSMutableArray<id<OWSReadTracking>> *interactionsToMarkAsRead = [NSMutableArray new];
 | 
			
		||||
 | 
			
		||||
            // Always mark the message specified by the read receipt as read.
 | 
			
		||||
            [interactionsToMarkAsRead addObject:message];
 | 
			
		||||
 | 
			
		||||
            [[TSDatabaseView unseenDatabaseViewExtension:transaction]
 | 
			
		||||
                enumerateRowsInGroup:message.uniqueThreadId
 | 
			
		||||
                          usingBlock:^(NSString *collection,
 | 
			
		||||
                              NSString *key,
 | 
			
		||||
                              id object,
 | 
			
		||||
                              id metadata,
 | 
			
		||||
                              NSUInteger index,
 | 
			
		||||
                              BOOL *stop) {
 | 
			
		||||
 | 
			
		||||
                              TSInteraction *interaction = object;
 | 
			
		||||
                              if (interaction.timestampForSorting > message.timestampForSorting) {
 | 
			
		||||
                                  *stop = YES;
 | 
			
		||||
                                  return;
 | 
			
		||||
                              }
 | 
			
		||||
 | 
			
		||||
                              id<OWSReadTracking> possiblyRead = (id<OWSReadTracking>)object;
 | 
			
		||||
                              OWSAssert(!possiblyRead.read);
 | 
			
		||||
                              [interactionsToMarkAsRead addObject:possiblyRead];
 | 
			
		||||
                          }];
 | 
			
		||||
 | 
			
		||||
            for (id<OWSReadTracking> interaction in interactionsToMarkAsRead) {
 | 
			
		||||
                // * Don't send a read receipt in response to a read receipt.
 | 
			
		||||
                // * Don't update expiration; we'll do that in the next statement.
 | 
			
		||||
                [interaction markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
 | 
			
		||||
 | 
			
		||||
                if ([interaction isKindOfClass:[TSMessage class]]) {
 | 
			
		||||
                    TSMessage *otherMessage = (TSMessage *)interaction;
 | 
			
		||||
 | 
			
		||||
                    // Update expiration using the timestamp from the readReceipt.
 | 
			
		||||
                    [OWSDisappearingMessagesJob setExpirationForMessage:otherMessage
 | 
			
		||||
                                                    expirationStartedAt:readReceipt.timestamp];
 | 
			
		||||
 | 
			
		||||
                    // Fire event that will cancel any pending notifications for this message.
 | 
			
		||||
                    [[NSNotificationCenter defaultCenter]
 | 
			
		||||
                     postNotificationNameAsync:OWSReadReceiptsProcessorMarkedMessageAsReadNotification
 | 
			
		||||
                     object:otherMessage];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If it was previously saved, no need to keep it around any longer.
 | 
			
		||||
            [readReceipt removeWithTransaction:transaction];
 | 
			
		||||
        } else {
 | 
			
		||||
            DDLogDebug(@"%@ Received read receipt for an unknown message. Saving it for later.", self.tag);
 | 
			
		||||
            [readReceipt saveWithTransaction:transaction];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
+ (NSString *)tag
 | 
			
		||||
{
 | 
			
		||||
    return [NSString stringWithFormat:@"[%@]", self.class];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)tag
 | 
			
		||||
{
 | 
			
		||||
    return self.class.tag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
NS_ASSUME_NONNULL_END
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue