Handle synced quotes

// FREEBIE
pull/1/head
Michael Kirk 7 years ago
parent 622f6bdf21
commit f1714bf252

@ -8,9 +8,11 @@
#import "OWSIncomingSentMessageTranscript.h"
#import "OWSPrimaryStorage+SessionStore.h"
#import "OWSReadReceiptManager.h"
#import "TSAttachmentPointer.h"
#import "TSInfoMessage.h"
#import "TSNetworkManager.h"
#import "TSOutgoingMessage.h"
#import "TSQuotedMessage.h"
#import "TextSecureKitEnv.h"
NS_ASSUME_NONNULL_BEGIN
@ -65,12 +67,11 @@ NS_ASSUME_NONNULL_BEGIN
OWSIncomingSentMessageTranscript *transcript = self.incomingSentMessageTranscript;
DDLogDebug(@"%@ Recording transcript: %@", self.logTag, transcript);
TSThread *thread = [transcript threadWithTransaction:transaction];
if (transcript.isEndSessionMessage) {
DDLogInfo(@"%@ EndSession was sent to recipient: %@.", self.logTag, transcript.recipientId);
[self.primaryStorage deleteAllSessionsForContact:transcript.recipientId protocolContext:transaction];
[[[TSInfoMessage alloc] initWithTimestamp:transcript.timestamp
inThread:thread
inThread:transcript.thread
messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction];
// Don't continue processing lest we print a bubble for the session reset.
@ -83,19 +84,50 @@ NS_ASSUME_NONNULL_BEGIN
networkManager:self.networkManager
transaction:transaction];
// TODO group updates. Currently desktop doesn't support group updates, so not a problem yet.
TSOutgoingMessage *outgoingMessage =
[[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:transcript.timestamp
inThread:thread
inThread:transcript.thread
messageBody:transcript.body
attachmentIds:[attachmentsProcessor.attachmentIds mutableCopy]
expiresInSeconds:transcript.expirationDuration
expireStartedAt:transcript.expirationStartedAt
isVoiceMessage:NO
groupMetaMessage:TSGroupMessageNone
quotedMessage:nil];
quotedMessage:transcript.quotedMessage];
TSQuotedMessage *_Nullable quotedMessage = transcript.quotedMessage;
if (quotedMessage && quotedMessage.thumbnailAttachmentPointerId) {
// We weren't able to derive a local thumbnail, so we'll fetch the referenced attachment.
TSAttachmentPointer *attachmentPointer =
[TSAttachmentPointer fetchObjectWithUniqueID:quotedMessage.thumbnailAttachmentPointerId
transaction:transaction];
if ([attachmentPointer isKindOfClass:[TSAttachmentPointer class]]) {
OWSAttachmentsProcessor *attachmentProcessor =
[[OWSAttachmentsProcessor alloc] initWithAttachmentPointer:attachmentPointer
networkManager:self.networkManager];
DDLogDebug(@"%@ downloading thumbnail for transcript: %tu", self.logTag, transcript.timestamp);
[attachmentProcessor fetchAttachmentsForMessage:outgoingMessage
transaction:transaction
success:^(TSAttachmentStream *_Nonnull attachmentStream) {
[self.primaryStorage.newDatabaseConnection
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[outgoingMessage setQuotedMessageThumbnailAttachmentStream:attachmentStream];
[outgoingMessage saveWithTransaction:transaction];
}];
}
failure:^(NSError *_Nonnull error) {
DDLogWarn(@"%@ failed to fetch thumbnail for transcript: %tu with error: %@",
self.logTag,
transcript.timestamp,
error);
}];
}
}
// TODO synced quoted replies
if (transcript.isExpirationTimerUpdate) {
[OWSDisappearingMessagesJob becomeConsistentWithConfigurationForMessage:outgoingMessage
contactsManager:self.contactsManager];

@ -41,11 +41,6 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey;
- (instancetype)initWithAttachmentPointer:(TSAttachmentPointer *)attachmentPointer
networkManager:(TSNetworkManager *)networkManager NS_DESIGNATED_INITIALIZER;
+ (TSAttachmentPointer *)buildPointerFromProto:(OWSSignalServiceProtosAttachmentPointer *)attachmentProto
relay:(NSString *_Nullable)relay;
- (void)fetchAttachmentsForMessage:(nullable TSMessage *)message
primaryStorage:(OWSPrimaryStorage *)primaryStorage
success:(void (^)(TSAttachmentStream *attachmentStream))successHandler

@ -72,7 +72,7 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
NSMutableArray<TSAttachmentPointer *> *attachmentPointers = [NSMutableArray new];
for (OWSSignalServiceProtosAttachmentPointer *attachmentProto in attachmentProtos) {
TSAttachmentPointer *pointer = [self.class buildPointerFromProto:attachmentProto relay:relay];
TSAttachmentPointer *pointer = [TSAttachmentPointer attachmentPointerFromProto:attachmentProto relay:relay];
[attachmentIds addObject:pointer.uniqueId];
[pointer saveWithTransaction:transaction];
@ -85,35 +85,6 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
return self;
}
+ (TSAttachmentPointer *)buildPointerFromProto:(OWSSignalServiceProtosAttachmentPointer *)attachmentProto
relay:(NSString *_Nullable)relay
{
OWSAssert(attachmentProto.id != 0);
OWSAssert(attachmentProto.key != nil);
OWSAssert(attachmentProto.contentType != nil);
// digest will be empty for old clients.
NSData *digest = attachmentProto.hasDigest ? attachmentProto.digest : nil;
TSAttachmentType attachmentType = TSAttachmentTypeDefault;
if ([attachmentProto hasFlags]) {
UInt32 flags = attachmentProto.flags;
if ((flags & (UInt32)OWSSignalServiceProtosAttachmentPointerFlagsVoiceMessage) > 0) {
attachmentType = TSAttachmentTypeVoiceMessage;
}
}
TSAttachmentPointer *pointer = [[TSAttachmentPointer alloc] initWithServerId:attachmentProto.id
key:attachmentProto.key
digest:digest
byteCount:attachmentProto.size
contentType:attachmentProto.contentType
relay:relay
sourceFilename:attachmentProto.fileName
attachmentType:attachmentType];
return pointer;
}
// PERF: Remove this and use a pre-existing dbConnection
- (void)fetchAttachmentsForMessage:(nullable TSMessage *)message
primaryStorage:(OWSPrimaryStorage *)primaryStorage

@ -1,7 +1,8 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "OWSSignalServiceProtos.pb.h"
#import "TSAttachment.h"
NS_ASSUME_NONNULL_BEGIN
@ -28,6 +29,9 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) {
sourceFilename:(nullable NSString *)sourceFilename
attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER;
+ (TSAttachmentPointer *)attachmentPointerFromProto:(OWSSignalServiceProtosAttachmentPointer *)attachmentProto
relay:(NSString *_Nullable)relay;
@property (nonatomic, readonly) NSString *relay;
@property (atomic) TSAttachmentPointerState state;
@property (nullable, atomic) NSString *mostRecentFailureLocalizedText;

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "TSAttachmentPointer.h"
@ -51,6 +51,36 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
+ (TSAttachmentPointer *)attachmentPointerFromProto:(OWSSignalServiceProtosAttachmentPointer *)attachmentProto
relay:(NSString *_Nullable)relay
{
OWSAssert(attachmentProto.id != 0);
OWSAssert(attachmentProto.key != nil);
OWSAssert(attachmentProto.contentType != nil);
// digest will be empty for old clients.
NSData *digest = attachmentProto.hasDigest ? attachmentProto.digest : nil;
TSAttachmentType attachmentType = TSAttachmentTypeDefault;
if ([attachmentProto hasFlags]) {
UInt32 flags = attachmentProto.flags;
if ((flags & (UInt32)OWSSignalServiceProtosAttachmentPointerFlagsVoiceMessage) > 0) {
attachmentType = TSAttachmentTypeVoiceMessage;
}
}
TSAttachmentPointer *pointer = [[TSAttachmentPointer alloc] initWithServerId:attachmentProto.id
key:attachmentProto.key
digest:digest
byteCount:attachmentProto.size
contentType:attachmentProto.contentType
relay:relay
sourceFilename:attachmentProto.fileName
attachmentType:attachmentType];
return pointer;
}
- (BOOL)isDecimalNumberText:(NSString *)text
{
return [text componentsSeparatedByCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]].count == 1;

@ -1,12 +1,13 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@class OWSSignalServiceProtosSyncMessageSent;
@class OWSSignalServiceProtosDataMessage;
@class OWSSignalServiceProtosAttachmentPointer;
@class OWSSignalServiceProtosDataMessage;
@class OWSSignalServiceProtosSyncMessageSent;
@class TSQuotedMessage;
@class TSThread;
@class YapDatabaseReadWriteTransaction;
@ -16,7 +17,9 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface OWSIncomingSentMessageTranscript : NSObject
- (instancetype)initWithProto:(OWSSignalServiceProtosSyncMessageSent *)sentProto relay:(NSString *)relay;
- (instancetype)initWithProto:(OWSSignalServiceProtosSyncMessageSent *)sentProto
relay:(nullable NSString *)relay
transaction:(YapDatabaseReadWriteTransaction *)transaction;
@property (nonatomic, readonly) NSString *relay;
@property (nonatomic, readonly) OWSSignalServiceProtosDataMessage *dataMessage;
@ -30,8 +33,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nullable, nonatomic, readonly) NSData *groupId;
@property (nonatomic, readonly) NSString *body;
@property (nonatomic, readonly) NSArray<OWSSignalServiceProtosAttachmentPointer *> *attachmentPointerProtos;
- (TSThread *)threadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
@property (nonatomic, readonly) TSThread *thread;
@property (nonatomic, readonly) TSQuotedMessage *quotedMessage;
@end

@ -10,13 +10,16 @@
#import "TSGroupModel.h"
#import "TSGroupThread.h"
#import "TSOutgoingMessage.h"
#import "TSQuotedMessage.h"
#import "TSThread.h"
NS_ASSUME_NONNULL_BEGIN
@implementation OWSIncomingSentMessageTranscript
- (instancetype)initWithProto:(OWSSignalServiceProtosSyncMessageSent *)sentProto relay:(NSString *)relay
- (instancetype)initWithProto:(OWSSignalServiceProtosSyncMessageSent *)sentProto
relay:(nullable NSString *)relay
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
self = [super init];
if (!self) {
@ -35,6 +38,15 @@ NS_ASSUME_NONNULL_BEGIN
_isExpirationTimerUpdate = (_dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsExpirationTimerUpdate) != 0;
_isEndSessionMessage = (_dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsEndSession) != 0;
if (self.dataMessage.hasGroup) {
_thread = [TSGroupThread getOrCreateThreadWithGroupId:_dataMessage.group.id transaction:transaction];
} else {
_thread = [TSContactThread getOrCreateThreadWithContactId:_recipientId transaction:transaction];
}
_quotedMessage =
[TSQuotedMessage quotedMessageForDataMessage:_dataMessage thread:_thread relay:relay transaction:transaction];
return self;
}
@ -47,15 +59,6 @@ NS_ASSUME_NONNULL_BEGIN
}
}
- (TSThread *)threadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
if (self.dataMessage.hasGroup) {
return [TSGroupThread getOrCreateThreadWithGroupId:self.dataMessage.group.id transaction:transaction];
} else {
return [TSContactThread getOrCreateThreadWithContactId:self.recipientId transaction:transaction];
}
}
@end
NS_ASSUME_NONNULL_END

@ -7,9 +7,13 @@
NS_ASSUME_NONNULL_BEGIN
@class OWSSignalServiceProtosDataMessage;
@class OWSSignalServiceProtosEnvelope;
@class TSAttachment;
@class TSAttachmentStream;
@class TSQuotedMessage;
@class TSThread;
@class YapDatabaseReadWriteTransaction;
// View model which has already fetched any attachments.
@interface OWSQuotedReplyModel : NSObject
@ -121,6 +125,12 @@ NS_ASSUME_NONNULL_BEGIN
body:(NSString *_Nullable)body
quotedAttachmentsForSending:(NSArray<TSAttachment *> *)attachments;
+ (nullable instancetype)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
thread:(TSThread *)thread
relay:(nullable NSString *)relay
transaction:(YapDatabaseReadWriteTransaction *)transaction;
@end
#pragma mark -

@ -3,8 +3,15 @@
//
#import "TSQuotedMessage.h"
#import "OWSSignalServiceProtos.pb.h"
#import "TSAccountManager.h"
#import "TSAttachment.h"
#import "TSAttachmentPointer.h"
#import "TSAttachmentStream.h"
#import "TSIncomingMessage.h"
#import "TSInteraction.h"
#import "TSOutgoingMessage.h"
#import "TSThread.h"
#import <YapDatabase/YapDatabaseTransaction.h>
NS_ASSUME_NONNULL_BEGIN
@ -178,6 +185,147 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
+ (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
thread:(TSThread *)thread
relay:(nullable NSString *)relay
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(dataMessage);
if (!dataMessage.hasQuote) {
return nil;
}
OWSSignalServiceProtosDataMessageQuote *quoteProto = [dataMessage quote];
if (![quoteProto hasId] || [quoteProto id] == 0) {
OWSFail(@"%@ quoted message missing id", self.logTag);
return nil;
}
uint64_t timestamp = [quoteProto id];
if (![quoteProto hasAuthor] || [quoteProto author].length == 0) {
OWSFail(@"%@ quoted message missing author", self.logTag);
return nil;
}
// TODO: We could verify that this is a valid e164 value.
NSString *authorId = [quoteProto author];
NSString *_Nullable body = nil;
BOOL hasText = NO;
BOOL hasAttachment = NO;
if ([quoteProto hasText] && [quoteProto text].length > 0) {
body = [quoteProto text];
hasText = YES;
}
NSMutableArray<OWSAttachmentInfo *> *attachmentInfos = [NSMutableArray new];
for (OWSSignalServiceProtosDataMessageQuoteQuotedAttachment *quotedAttachment in quoteProto.attachments) {
hasAttachment = YES;
OWSAttachmentInfo *attachmentInfo = [[OWSAttachmentInfo alloc] initWithAttachmentId:nil
contentType:quotedAttachment.contentType
sourceFilename:quotedAttachment.fileName];
// We prefer deriving any thumbnail locally rather than fetching one from the network.
TSAttachmentStream *_Nullable thumbnailStream =
[self tryToDeriveLocalThumbnailWithAttachmentInfo:attachmentInfo
timestamp:timestamp
threadId:thread.uniqueId
authorId:authorId
transaction:transaction];
if (thumbnailStream) {
DDLogDebug(@"%@ Generated local thumbnail for quoted quoted message: %@:%tu",
self.logTag,
thread.uniqueId,
timestamp);
[thumbnailStream saveWithTransaction:transaction];
attachmentInfo.thumbnailAttachmentStreamId = thumbnailStream.uniqueId;
} else if (quotedAttachment.hasThumbnail) {
DDLogDebug(@"%@ Saving reference for fetching remote thumbnail for quoted message: %@:%tu",
self.logTag,
thread.uniqueId,
timestamp);
OWSSignalServiceProtosAttachmentPointer *thumbnailAttachmentProto = quotedAttachment.thumbnail;
TSAttachmentPointer *thumbnailPointer =
[TSAttachmentPointer attachmentPointerFromProto:thumbnailAttachmentProto relay:relay];
[thumbnailPointer saveWithTransaction:transaction];
attachmentInfo.thumbnailAttachmentPointerId = thumbnailPointer.uniqueId;
} else {
DDLogDebug(@"%@ No thumbnail for quoted message: %@:%tu", self.logTag, thread.uniqueId, timestamp);
}
[attachmentInfos addObject:attachmentInfo];
}
if (!hasText && !hasAttachment) {
OWSFail(@"%@ quoted message has neither text nor attachment", self.logTag);
return nil;
}
return [[TSQuotedMessage alloc] initWithTimestamp:timestamp
authorId:authorId
body:body
quotedAttachmentInfos:attachmentInfos];
}
+ (nullable TSAttachmentStream *)tryToDeriveLocalThumbnailWithAttachmentInfo:(OWSAttachmentInfo *)attachmentInfo
timestamp:(uint64_t)timestamp
threadId:(NSString *)threadId
authorId:(NSString *)authorId
transaction:
(YapDatabaseReadWriteTransaction *)transaction
{
if (![TSAttachmentStream hasThumbnailForMimeType:attachmentInfo.contentType]) {
return nil;
}
NSArray<TSMessage *> *quotedMessages = (NSArray<TSMessage *> *)[TSInteraction
interactionsWithTimestamp:timestamp
filter:^BOOL(TSInteraction *interaction) {
if (![threadId isEqual:interaction.uniqueThreadId]) {
return NO;
}
if ([interaction isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)interaction;
return [authorId isEqual:incomingMessage.messageAuthorId];
} else if ([interaction isKindOfClass:[TSOutgoingMessage class]]) {
return [authorId isEqual:[TSAccountManager localNumber]];
} else {
// ignore other interaction types
return NO;
}
}
withTransaction:transaction];
TSMessage *_Nullable quotedMessage = quotedMessages.firstObject;
if (!quotedMessage) {
return nil;
}
TSAttachment *attachment = [quotedMessage attachmentWithTransaction:transaction];
if (![attachment isKindOfClass:[TSAttachmentStream class]]) {
return nil;
}
TSAttachmentStream *sourceStream = (TSAttachmentStream *)attachment;
TSAttachmentStream *_Nullable thumbnailStream = [sourceStream cloneAsThumbnail];
if (!thumbnailStream) {
return nil;
}
return thumbnailStream;
}
#pragma mark - Attachment (not necessarily with a thumbnail)
- (nullable OWSAttachmentInfo *)firstAttachmentInfo

@ -603,7 +603,9 @@ NS_ASSUME_NONNULL_BEGIN
if (syncMessage.hasSent) {
OWSIncomingSentMessageTranscript *transcript =
[[OWSIncomingSentMessageTranscript alloc] initWithProto:syncMessage.sent relay:envelope.relay];
[[OWSIncomingSentMessageTranscript alloc] initWithProto:syncMessage.sent
relay:envelope.relay
transaction:transaction];
OWSRecordTranscriptJob *recordJob =
[[OWSRecordTranscriptJob alloc] initWithIncomingSentMessageTranscript:transcript];
@ -989,10 +991,10 @@ NS_ASSUME_NONNULL_BEGIN
return nil;
}
TSQuotedMessage *_Nullable quotedMessage = [self quotedMessageForDataMessage:dataMessage
envelope:envelope
thread:oldGroupThread
transaction:transaction];
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
thread:oldGroupThread
relay:envelope.relay
transaction:transaction];
DDLogDebug(@"%@ incoming message from: %@ for group: %@ with timestamp: %lu",
self.logTag,
@ -1038,8 +1040,10 @@ NS_ASSUME_NONNULL_BEGIN
transaction:transaction
relay:envelope.relay];
TSQuotedMessage *_Nullable quotedMessage =
[self quotedMessageForDataMessage:dataMessage envelope:envelope thread:thread transaction:transaction];
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
thread:thread
relay:envelope.relay
transaction:transaction];
TSIncomingMessage *incomingMessage =
[[TSIncomingMessage alloc] initIncomingMessageWithTimestamp:timestamp
@ -1059,147 +1063,6 @@ NS_ASSUME_NONNULL_BEGIN
}
}
- (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
envelope:(OWSSignalServiceProtosEnvelope *)envelope
thread:(TSThread *)thread
transaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssert(dataMessage);
if (!dataMessage.hasQuote) {
return nil;
}
OWSSignalServiceProtosDataMessageQuote *quoteProto = [dataMessage quote];
if (![quoteProto hasId] || [quoteProto id] == 0) {
OWSFail(@"%@ quoted message missing id", self.logTag);
return nil;
}
uint64_t timestamp = [quoteProto id];
if (![quoteProto hasAuthor] || [quoteProto author].length == 0) {
OWSFail(@"%@ quoted message missing author", self.logTag);
return nil;
}
// TODO: We could verify that this is a valid e164 value.
NSString *authorId = [quoteProto author];
NSString *_Nullable body = nil;
BOOL hasText = NO;
BOOL hasAttachment = NO;
if ([quoteProto hasText] && [quoteProto text].length > 0) {
body = [quoteProto text];
hasText = YES;
}
NSMutableArray<OWSAttachmentInfo *> *attachmentInfos = [NSMutableArray new];
for (OWSSignalServiceProtosDataMessageQuoteQuotedAttachment *quotedAttachment in quoteProto.attachments) {
hasAttachment = YES;
OWSAttachmentInfo *attachmentInfo =
[[OWSAttachmentInfo alloc] initWithAttachmentId:nil
contentType:quotedAttachment.contentType
sourceFilename:quotedAttachment.fileName];
// We prefer deriving any thumbnail locally rather than fetching one from the network.
TSAttachmentStream *_Nullable thumbnailStream =
[self tryToDeriveLocalThumbnailWithAttachmentInfo:attachmentInfo
timestamp:timestamp
threadId:thread.uniqueId
authorId:authorId
transaction:transaction];
if (thumbnailStream) {
DDLogDebug(@"%@ Generated local thumbnail for quoted quoted message: %@:%zu",
self.logTag,
thread.uniqueId,
timestamp);
[thumbnailStream saveWithTransaction:transaction];
attachmentInfo.thumbnailAttachmentStreamId = thumbnailStream.uniqueId;
} else if (quotedAttachment.hasThumbnail) {
DDLogDebug(@"%@ Saving reference for fetching remote thumbnail for quoted message: %@:%zu",
self.logTag,
thread.uniqueId,
timestamp);
OWSSignalServiceProtosAttachmentPointer *thumbnailAttachmentProto = quotedAttachment.thumbnail;
TSAttachmentPointer *thumbnailPointer =
[OWSAttachmentsProcessor buildPointerFromProto:thumbnailAttachmentProto relay:envelope.relay];
[thumbnailPointer saveWithTransaction:transaction];
attachmentInfo.thumbnailAttachmentPointerId = thumbnailPointer.uniqueId;
} else {
DDLogDebug(@"%@ No thumbnail for quoted message: %@:%zu", self.logTag, thread.uniqueId, timestamp);
}
[attachmentInfos addObject:attachmentInfo];
}
if (!hasText && !hasAttachment) {
OWSFail(@"%@ quoted message has neither text nor attachment", self.logTag);
return nil;
}
return [[TSQuotedMessage alloc] initWithTimestamp:timestamp
authorId:authorId
body:body
quotedAttachmentInfos:attachmentInfos];
}
- (nullable TSAttachmentStream *)tryToDeriveLocalThumbnailWithAttachmentInfo:(OWSAttachmentInfo *)attachmentInfo
timestamp:(uint64_t)timestamp
threadId:(NSString *)threadId
authorId:(NSString *)authorId
transaction:
(YapDatabaseReadWriteTransaction *)transaction
{
if (![TSAttachmentStream hasThumbnailForMimeType:attachmentInfo.contentType]) {
return nil;
}
NSArray<TSMessage *> *quotedMessages = (NSArray<TSMessage *> *)[TSInteraction
interactionsWithTimestamp:timestamp
filter:^BOOL(TSInteraction *interaction) {
if (![threadId isEqual:interaction.uniqueThreadId]) {
return NO;
}
if ([interaction isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)interaction;
return [authorId isEqual:incomingMessage.messageAuthorId];
} else if ([interaction isKindOfClass:[TSOutgoingMessage class]]) {
return [authorId isEqual:[TSAccountManager localNumber]];
} else {
// ignore other interaction types
return NO;
}
}
withTransaction:transaction];
TSMessage *_Nullable quotedMessage = quotedMessages.firstObject;
if (!quotedMessage) {
return nil;
}
TSAttachment *attachment = [quotedMessage attachmentWithTransaction:transaction];
if (![attachment isKindOfClass:[TSAttachmentStream class]]) {
return nil;
}
TSAttachmentStream *sourceStream = (TSAttachmentStream *)attachment;
TSAttachmentStream *_Nullable thumbnailStream = [sourceStream cloneAsThumbnail];
if (!thumbnailStream) {
return nil;
}
return thumbnailStream;
}
- (void)finalizeIncomingMessage:(TSIncomingMessage *)incomingMessage
thread:(TSThread *)thread
envelope:(OWSSignalServiceProtosEnvelope *)envelope

Loading…
Cancel
Save