// // Copyright (c) 2017 Open Whisper Systems. All rights reserved. // #import "OWSRecordTranscriptJob.h" #import "OWSAttachmentsProcessor.h" #import "OWSIncomingSentMessageTranscript.h" #import "OWSMessageSender.h" #import "TSInfoMessage.h" #import "TSOutgoingMessage.h" #import "TSStorageManager+SessionStore.h" NS_ASSUME_NONNULL_BEGIN @interface OWSRecordTranscriptJob () @property (nonatomic, readonly) OWSIncomingSentMessageTranscript *incomingSentMessageTranscript; @property (nonatomic, readonly) OWSMessageSender *messageSender; @property (nonatomic, readonly) TSNetworkManager *networkManager; @property (nonatomic, readonly) TSStorageManager *storageManager; @end @implementation OWSRecordTranscriptJob - (instancetype)initWithIncomingSentMessageTranscript:(OWSIncomingSentMessageTranscript *)incomingSentMessageTranscript messageSender:(OWSMessageSender *)messageSender networkManager:(TSNetworkManager *)networkManager { self = [super init]; if (!self) { return self; } _incomingSentMessageTranscript = incomingSentMessageTranscript; _messageSender = messageSender; _networkManager = networkManager; _storageManager = [TSStorageManager sharedManager]; return self; } - (void)runWithAttachmentHandler:(void (^)(TSAttachmentStream *attachmentStream))attachmentHandler transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(transaction); OWSIncomingSentMessageTranscript *transcript = self.incomingSentMessageTranscript; DDLogDebug(@"%@ Recording transcript: %@", self.tag, transcript); TSThread *thread = [transcript threadWithTransaction:transaction]; if (transcript.isEndSessionMessage) { DDLogInfo(@"%@ EndSession was sent to recipient: %@.", self.tag, transcript.recipientId); dispatch_async([OWSDispatch sessionStoreQueue], ^{ [self.storageManager deleteAllSessionsForContact:transcript.recipientId]; }); [[[TSInfoMessage alloc] initWithTimestamp:transcript.timestamp inThread:thread messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction]; // Don't continue processing lest we print a bubble for the session reset. return; } OWSAttachmentsProcessor *attachmentsProcessor = [[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:transcript.attachmentPointerProtos timestamp:transcript.timestamp relay:transcript.relay thread:thread networkManager:self.networkManager storageManager:self.storageManager transaction:transaction]; // TODO group updates. Currently desktop doesn't support group updates, so not a problem yet. TSOutgoingMessage *outgoingMessage = [[TSOutgoingMessage alloc] initWithTimestamp:transcript.timestamp inThread:thread messageBody:transcript.body attachmentIds:[attachmentsProcessor.attachmentIds mutableCopy] expiresInSeconds:transcript.expirationDuration expireStartedAt:transcript.expirationStartedAt]; if (transcript.isExpirationTimerUpdate) { [self.messageSender becomeConsistentWithDisappearingConfigurationForMessage:outgoingMessage]; // early return to avoid saving an empty incoming message. return; } [self.messageSender handleMessageSentRemotely:outgoingMessage sentAt:transcript.expirationStartedAt transaction:transaction]; [attachmentsProcessor fetchAttachmentsForMessage:outgoingMessage transaction:transaction success:attachmentHandler failure:^(NSError *_Nonnull error) { DDLogError(@"%@ failed to fetch transcripts attachments for message: %@", self.tag, outgoingMessage); }]; // If there is an attachment + text, render the text here, as Signal-iOS renders two messages. if (attachmentsProcessor.hasSupportedAttachments && transcript.body && ![transcript.body isEqualToString:@""]) { // We want the text to appear after the attachment. uint64_t textMessageTimestamp = transcript.timestamp + 1; TSOutgoingMessage *textMessage = [[TSOutgoingMessage alloc] initWithTimestamp:textMessageTimestamp inThread:thread messageBody:transcript.body attachmentIds:[NSMutableArray new] expiresInSeconds:transcript.expirationDuration expireStartedAt:transcript.expirationStartedAt]; // Since textMessage is a new message, updateWithWasSentAndDelivered will save it. [textMessage updateWithWasSentFromLinkedDeviceWithTransaction:transaction]; } } #pragma mark - Logging + (NSString *)tag { return [NSString stringWithFormat:@"[%@]", self.class]; } - (NSString *)tag { return self.class.tag; } @end NS_ASSUME_NONNULL_END