From ed047ac51293a31101483053e3cbafa2b4be865f Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 5 May 2021 14:50:46 +1000 Subject: [PATCH] More cleanup --- .../Messages/Signal/TSOutgoingMessage.h | 37 -- .../Messages/Signal/TSOutgoingMessage.m | 474 +----------------- 2 files changed, 3 insertions(+), 508 deletions(-) diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h index 61958afc8..6a97cfc0c 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.h @@ -19,9 +19,6 @@ typedef NS_ENUM(NSInteger, TSOutgoingMessageState) { TSOutgoingMessageStateSending, // The failure state. TSOutgoingMessageStateFailed, - // These two enum values have been combined into TSOutgoingMessageStateSent. - TSOutgoingMessageStateSent_OBSOLETE, - TSOutgoingMessageStateDelivered_OBSOLETE, // The message has been sent to the service. TSOutgoingMessageStateSent, }; @@ -133,42 +130,8 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { @property (nonatomic, readonly) BOOL isVoiceMessage; -// This property won't be accurate for legacy messages. -@property (atomic, readonly) BOOL isFromLinkedDevice; - -@property (nonatomic, readonly) BOOL isSilent; - -@property (nonatomic, readonly) BOOL isOnline; - -@property (nonatomic, readonly) uint ttl; - + (nullable instancetype)findMessageWithTimestamp:(uint64_t)timestamp; -/** - * The data representation of this message, to be encrypted, before being sent. - */ -- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient; - -/** - * Intermediate protobuf representation - * Subclasses can augment if they want to manipulate the data message before building. - */ -- (nullable id)dataMessageBuilder; - -- (nullable SNProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId; - -/** - * Allows subclasses to supply a custom content builder that has already prepared part of the message. - */ -- (nullable id)prepareCustomContentBuilder:(SignalRecipient *)recipient; - -/** - * Should this message be synced to the users other registered devices? This is - * generally always true, except in the case of the sync messages themseleves - * (so we don't end up in an infinite loop). - */ -- (BOOL)shouldSyncTranscript; - - (BOOL)shouldBeSaved; // All recipients of this message. diff --git a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m index 5c6b0a771..95f2f6409 100644 --- a/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m +++ b/SessionMessagingKit/Messages/Signal/TSOutgoingMessage.m @@ -37,10 +37,6 @@ NSString *NSStringForOutgoingMessageState(TSOutgoingMessageState value) return @"TSOutgoingMessageStateSending"; case TSOutgoingMessageStateFailed: return @"TSOutgoingMessageStateFailed"; - case TSOutgoingMessageStateSent_OBSOLETE: - return @"TSOutgoingMessageStateSent_OBSOLETE"; - case TSOutgoingMessageStateDelivered_OBSOLETE: - return @"TSOutgoingMessageStateDelivered_OBSOLETE"; case TSOutgoingMessageStateSent: return @"TSOutgoingMessageStateSent"; } @@ -82,13 +78,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt @property (atomic) BOOL hasSyncedTranscript; @property (atomic) NSString *customMessage; @property (atomic) NSString *mostRecentFailureText; -@property (atomic) BOOL isFromLinkedDevice; @property (atomic) TSGroupMetaMessage groupMetaMessage; - -@property (nonatomic, readonly) TSOutgoingMessageState legacyMessageState; -@property (nonatomic, readonly) BOOL legacyWasDelivered; -@property (nonatomic, readonly) BOOL hasLegacyMessageState; - @property (atomic, nullable) NSDictionary *recipientStateMap; @end @@ -105,118 +95,11 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt if (!_attachmentFilenameMap) { _attachmentFilenameMap = [NSMutableDictionary new]; } - - if (!self.recipientStateMap) { - [self migrateRecipientStateMapWithCoder:coder]; - } } return self; } -- (void)migrateRecipientStateMapWithCoder:(NSCoder *)coder -{ - // Determine the "overall message state." - TSOutgoingMessageState oldMessageState = TSOutgoingMessageStateFailed; - NSNumber *_Nullable messageStateValue = [coder decodeObjectForKey:@"messageState"]; - if (messageStateValue) { - oldMessageState = (TSOutgoingMessageState)messageStateValue.intValue; - } - _hasLegacyMessageState = YES; - _legacyMessageState = oldMessageState; - - OWSOutgoingMessageRecipientState defaultState; - switch (oldMessageState) { - case TSOutgoingMessageStateFailed: - defaultState = OWSOutgoingMessageRecipientStateFailed; - break; - case TSOutgoingMessageStateSending: - defaultState = OWSOutgoingMessageRecipientStateSending; - break; - case TSOutgoingMessageStateSent: - case TSOutgoingMessageStateSent_OBSOLETE: - case TSOutgoingMessageStateDelivered_OBSOLETE: - // Convert legacy values. - defaultState = OWSOutgoingMessageRecipientStateSent; - break; - } - - // Try to leverage the "per-recipient state." - NSDictionary *_Nullable recipientDeliveryMap = - [coder decodeObjectForKey:@"recipientDeliveryMap"]; - NSDictionary *_Nullable recipientReadMap = [coder decodeObjectForKey:@"recipientReadMap"]; - NSArray *_Nullable sentRecipients = [coder decodeObjectForKey:@"sentRecipients"]; - - NSMutableDictionary *recipientStateMap = [NSMutableDictionary new]; - __block BOOL isGroupThread = NO; - // Our default recipient list is the current thread members. - __block NSArray *recipientIds = @[]; - // To avoid deadlock while migrating these records, we use a dedicated - // migration connection. For legacy records (created more than ~9 months - // before the migration), we need to infer the recipient list for this - // message from the current thread membership. This inference isn't - // always accurate, so not using the same connection for both reads is - // acceptable. - [TSOutgoingMessage.dbMigrationConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - TSThread *thread = [self threadWithTransaction:transaction]; - recipientIds = [thread recipientIdentifiers]; - isGroupThread = [thread isGroupThread]; - }]; - - NSNumber *_Nullable wasDelivered = [coder decodeObjectForKey:@"wasDelivered"]; - _legacyWasDelivered = wasDelivered && wasDelivered.boolValue; - BOOL wasDeliveredToContact = NO; - if (isGroupThread) { - // If we have a `sentRecipients` list, prefer that as it is more accurate. - if (sentRecipients) { - recipientIds = sentRecipients; - } - } else { - // Special-case messages in contact threads; if "was delivered", we know - // it was delivered to the contact. - wasDeliveredToContact = _legacyWasDelivered; - } - - NSString *_Nullable singleGroupRecipient = [coder decodeObjectForKey:@"singleGroupRecipient"]; - if (singleGroupRecipient) { - // If this is a "single group recipient message", treat it as such. - recipientIds = @[ - singleGroupRecipient, - ]; - } - - for (NSString *recipientId in recipientIds) { - TSOutgoingMessageRecipientState *recipientState = [TSOutgoingMessageRecipientState new]; - - NSNumber *_Nullable readTimestamp = recipientReadMap[recipientId]; - NSNumber *_Nullable deliveryTimestamp = recipientDeliveryMap[recipientId]; - if (readTimestamp) { - // If we have a read timestamp for this recipient, mark it as read. - recipientState.state = OWSOutgoingMessageRecipientStateSent; - recipientState.readTimestamp = readTimestamp; - // deliveryTimestamp might be nil here. - recipientState.deliveryTimestamp = deliveryTimestamp; - } else if (deliveryTimestamp) { - // If we have a delivery timestamp for this recipient, mark it as delivered. - recipientState.state = OWSOutgoingMessageRecipientStateSent; - recipientState.deliveryTimestamp = deliveryTimestamp; - } else if (wasDeliveredToContact) { - recipientState.state = OWSOutgoingMessageRecipientStateSent; - // Use message time as an estimate of delivery time. - recipientState.deliveryTimestamp = @(self.timestamp); - } else if ([sentRecipients containsObject:recipientId]) { - // If this recipient is in `sentRecipients`, mark it as sent. - recipientState.state = OWSOutgoingMessageRecipientStateSent; - } else { - // Use the default state for this message. - recipientState.state = defaultState; - } - - recipientStateMap[recipientId] = recipientState; - } - self.recipientStateMap = [recipientStateMap copy]; -} - + (YapDatabaseConnection *)dbMigrationConnection { return SSKEnvironment.shared.migrationDBConnection; @@ -380,30 +263,17 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt - (TSOutgoingMessageState)messageState { - TSOutgoingMessageState newMessageState = - [TSOutgoingMessage messageStateForRecipientStates:self.recipientStateMap.allValues]; - if (self.hasLegacyMessageState) { - if (newMessageState == TSOutgoingMessageStateSent || self.legacyMessageState == TSOutgoingMessageStateSent) { - return TSOutgoingMessageStateSent; - } - } - return newMessageState; + return [TSOutgoingMessage messageStateForRecipientStates:self.recipientStateMap.allValues]; } - (BOOL)wasDeliveredToAnyRecipient { - if ([self deliveredRecipientIds].count > 0) { - return YES; - } - return (self.hasLegacyMessageState && self.legacyWasDelivered && self.messageState == TSOutgoingMessageStateSent); + return [self deliveredRecipientIds].count > 0; } - (BOOL)wasSentToAnyRecipient { - if ([self sentRecipientIds].count > 0) { - return YES; - } - return (self.hasLegacyMessageState && self.messageState == TSOutgoingMessageStateSent); + return [self sentRecipientIds].count > 0; } + (TSOutgoingMessageState)messageStateForRecipientStates:(NSArray *)recipientStates @@ -477,16 +347,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } } -- (BOOL)isSilent -{ - return NO; -} - -- (BOOL)isOnline -{ - return NO; -} - + (nullable instancetype)findMessageWithTimestamp:(uint64_t)timestamp { __block TSOutgoingMessage *result; @@ -620,15 +480,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt }]; } -- (void)updateWithHasSyncedTranscript:(BOOL)hasSyncedTranscript - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSOutgoingMessage *message) { - [message setHasSyncedTranscript:hasSyncedTranscript]; - }]; -} - - (void)updateWithCustomMessage:(NSString *)customMessage transaction:(YapDatabaseReadWriteTransaction *)transaction { [self applyChangeToSelfAndLatestCopy:transaction @@ -700,325 +551,6 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt }]; } -- (void)updateWithWasSentFromLinkedDeviceWithUDRecipientIds:(nullable NSArray *)udRecipientIds - nonUdRecipientIds:(nullable NSArray *)nonUdRecipientIds - isSentUpdate:(BOOL)isSentUpdate - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [self - applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSOutgoingMessage *message) { - if (udRecipientIds.count > 0 || nonUdRecipientIds.count > 0) { - // If we have specific recipient info from the transcript, - // build a new recipient state map. - NSMutableDictionary *recipientStateMap - = [NSMutableDictionary new]; - for (NSString *recipientId in udRecipientIds) { - if (recipientStateMap[recipientId]) { - continue; - } - TSOutgoingMessageRecipientState *recipientState = - [TSOutgoingMessageRecipientState new]; - recipientState.state = OWSOutgoingMessageRecipientStateSent; - recipientState.wasSentByUD = YES; - recipientStateMap[recipientId] = recipientState; - } - for (NSString *recipientId in nonUdRecipientIds) { - if (recipientStateMap[recipientId]) { - continue; - } - TSOutgoingMessageRecipientState *recipientState = - [TSOutgoingMessageRecipientState new]; - recipientState.state = OWSOutgoingMessageRecipientStateSent; - recipientState.wasSentByUD = NO; - recipientStateMap[recipientId] = recipientState; - } - - if (isSentUpdate) { - // If this is a "sent update", make sure that: - // - // a) "Sent updates" should never remove any recipients. We end up with the - // union of the existing and new recipients. - // b) "Sent updates" should never downgrade the "recipient state" for any - // recipients. Prefer existing "recipient state"; "sent updates" only - // add new recipients at the "sent" state. - // - // Therefore we retain all existing entries in the recipient state map. - [recipientStateMap addEntriesFromDictionary:self.recipientStateMap]; - } - - [message setRecipientStateMap:recipientStateMap]; - } else { - // Otherwise assume this is a legacy message before UD was introduced, and mark - // any "sending" recipient as "sent". Note that this will apply to non-legacy - // messages with no recipients. - for (TSOutgoingMessageRecipientState *recipientState in message.recipientStateMap - .allValues) { - if (recipientState.state == OWSOutgoingMessageRecipientStateSending) { - recipientState.state = OWSOutgoingMessageRecipientStateSent; - } - } - } - - if (!isSentUpdate) { - [message setIsFromLinkedDevice:YES]; - } - }]; -} - -- (void)updateWithSendingToSingleGroupRecipient:(NSString *)singleGroupRecipient - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSOutgoingMessage *message) { - TSOutgoingMessageRecipientState *recipientState = - [TSOutgoingMessageRecipientState new]; - recipientState.state = OWSOutgoingMessageRecipientStateSending; - [message setRecipientStateMap:@{ - singleGroupRecipient : recipientState, - }]; - }]; -} - -- (nullable NSNumber *)firstRecipientReadTimestamp -{ - NSNumber *result = nil; - for (TSOutgoingMessageRecipientState *recipientState in self.recipientStateMap.allValues) { - if (!recipientState.readTimestamp) { - continue; - } - if (!result || (result.unsignedLongLongValue > recipientState.readTimestamp.unsignedLongLongValue)) { - result = recipientState.readTimestamp; - } - } - return result; -} - -- (void)updateWithFakeMessageState:(TSOutgoingMessageState)messageState - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - [self applyChangeToSelfAndLatestCopy:transaction - changeBlock:^(TSOutgoingMessage *message) { - for (TSOutgoingMessageRecipientState *recipientState in message.recipientStateMap - .allValues) { - switch (messageState) { - case TSOutgoingMessageStateSending: - recipientState.state = OWSOutgoingMessageRecipientStateSending; - break; - case TSOutgoingMessageStateFailed: - recipientState.state = OWSOutgoingMessageRecipientStateFailed; - break; - case TSOutgoingMessageStateSent: - recipientState.state = OWSOutgoingMessageRecipientStateSent; - break; - default: - break; - } - } - }]; -} - -#pragma mark - - -- (nullable id)dataMessageBuilder -{ - TSThread *thread = self.thread; - - SNProtoDataMessageBuilder *builder = [SNProtoDataMessage builder]; - [builder setTimestamp:self.timestamp]; - - if ([self.body lengthOfBytesUsingEncoding:NSUTF8StringEncoding] <= kOversizeTextMessageSizeThreshold) { - [builder setBody:self.body]; - } else { - NSString *truncatedBody = [self.body copy]; - while ([truncatedBody lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > kOversizeTextMessageSizeThreshold) { - truncatedBody = [truncatedBody substringToIndex:truncatedBody.length / 2]; - } - [builder setBody:truncatedBody]; - } - [builder setExpireTimer:self.expiresInSeconds]; - - // Group Messages - BOOL attachmentWasGroupAvatar = NO; - if ([thread isKindOfClass:[TSGroupThread class]]) { - TSGroupThread *gThread = (TSGroupThread *)thread; - SNProtoGroupContextType groupMessageType; - switch (self.groupMetaMessage) { - case TSGroupMetaMessageQuit: - groupMessageType = SNProtoGroupContextTypeQuit; - break; - case TSGroupMetaMessageUpdate: - case TSGroupMetaMessageNew: - groupMessageType = SNProtoGroupContextTypeUpdate; - break; - default: - groupMessageType = SNProtoGroupContextTypeDeliver; - break; - } - SNProtoGroupContextBuilder *groupBuilder = - [SNProtoGroupContext builderWithId:gThread.groupModel.groupId type:groupMessageType]; - if (groupMessageType == SNProtoGroupContextTypeUpdate) { - if (gThread.groupModel.groupImage != nil && self.attachmentIds.count == 1) { - attachmentWasGroupAvatar = YES; - SNProtoAttachmentPointer *_Nullable attachmentProto = - [TSAttachmentStream buildProtoForAttachmentId:self.attachmentIds.firstObject]; - if (!attachmentProto) { - return nil; - } - [groupBuilder setAvatar:attachmentProto]; - } - - [groupBuilder setMembers:gThread.groupModel.groupMemberIds]; - [groupBuilder setName:gThread.groupModel.groupName]; - [groupBuilder setAdmins:gThread.groupModel.groupAdminIds]; - } - NSError *error; - SNProtoGroupContext *_Nullable groupContextProto = [groupBuilder buildAndReturnError:&error]; - if (error || !groupContextProto) { - return nil; - } - [builder setGroup:groupContextProto]; - } - - // Message Attachments - if (!attachmentWasGroupAvatar) { - NSMutableArray *attachments = [NSMutableArray new]; - for (NSString *attachmentId in self.attachmentIds) { - SNProtoAttachmentPointer *_Nullable attachmentProto = - [TSAttachmentStream buildProtoForAttachmentId:attachmentId]; - if (!attachmentProto) { - return nil; - } - [attachments addObject:attachmentProto]; - } - [builder setAttachments:attachments]; - } - - // Quoted Reply - SNProtoDataMessageQuoteBuilder *_Nullable quotedMessageBuilder = self.quotedMessageBuilder; - if (quotedMessageBuilder) { - NSError *error; - SNProtoDataMessageQuote *_Nullable quoteProto = [quotedMessageBuilder buildAndReturnError:&error]; - if (error || !quoteProto) { - return nil; - } - [builder setQuote:quoteProto]; - } - - // Link Preview - if (self.linkPreview) { - SNProtoDataMessagePreviewBuilder *previewBuilder = - [SNProtoDataMessagePreview builderWithUrl:self.linkPreview.urlString]; - if (self.linkPreview.title.length > 0) { - [previewBuilder setTitle:self.linkPreview.title]; - } - if (self.linkPreview.imageAttachmentId) { - SNProtoAttachmentPointer *_Nullable attachmentProto = - [TSAttachmentStream buildProtoForAttachmentId:self.linkPreview.imageAttachmentId]; - if (!attachmentProto) { - - } else { - [previewBuilder setImage:attachmentProto]; - } - } - - NSError *error; - SNProtoDataMessagePreview *_Nullable previewProto = [previewBuilder buildAndReturnError:&error]; - if (error || !previewProto) { - - } else { - [builder addPreview:previewProto]; - } - } - - return builder; -} - -- (nullable SNProtoDataMessageQuoteBuilder *)quotedMessageBuilder -{ - if (!self.quotedMessage) { - return nil; - } - TSQuotedMessage *quotedMessage = self.quotedMessage; - - SNProtoDataMessageQuoteBuilder *quoteBuilder = - [SNProtoDataMessageQuote builderWithId:quotedMessage.timestamp author:quotedMessage.authorId]; - - BOOL hasQuotedText = NO; - BOOL hasQuotedAttachment = NO; - if (self.quotedMessage.body.length > 0) { - hasQuotedText = YES; - [quoteBuilder setText:quotedMessage.body]; - } - - if (quotedMessage.quotedAttachments) { - for (OWSAttachmentInfo *attachment in quotedMessage.quotedAttachments) { - hasQuotedAttachment = YES; - - SNProtoDataMessageQuoteQuotedAttachmentBuilder *quotedAttachmentBuilder = - [SNProtoDataMessageQuoteQuotedAttachment builder]; - - quotedAttachmentBuilder.contentType = attachment.contentType; - quotedAttachmentBuilder.fileName = attachment.sourceFilename; - if (attachment.thumbnailAttachmentStreamId) { - quotedAttachmentBuilder.thumbnail = - [TSAttachmentStream buildProtoForAttachmentId:attachment.thumbnailAttachmentStreamId]; - } - - NSError *error; - SNProtoDataMessageQuoteQuotedAttachment *_Nullable quotedAttachmentMessage = - [quotedAttachmentBuilder buildAndReturnError:&error]; - if (error || !quotedAttachmentMessage) { - return nil; - } - - [quoteBuilder addAttachments:quotedAttachmentMessage]; - } - } - - if (hasQuotedText || hasQuotedAttachment) { - return quoteBuilder; - } else { - return nil; - } -} - -// recipientId is nil when building "sent" sync messages for messages sent to groups. -- (nullable SNProtoDataMessage *)buildDataMessage:(NSString *_Nullable)recipientId -{ - return nil; // Shouldn't be in use anymore -} - -- (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient -{ - SNProtoContentBuilder *contentBuilder = [self prepareCustomContentBuilder:recipient]; - - NSError *error; - NSData *_Nullable contentData = [contentBuilder buildSerializedDataAndReturnError:&error]; - if (error != nil || contentData == nil) { - return nil; - } - - return contentData; -} - -- (BOOL)shouldSyncTranscript -{ - return YES; -} - -- (NSString *)statusDescription -{ - NSMutableString *result = [NSMutableString new]; - [result appendFormat:@"[status: %@", NSStringForOutgoingMessageState(self.messageState)]; - for (NSString *recipientId in self.recipientStateMap) { - TSOutgoingMessageRecipientState *recipientState = self.recipientStateMap[recipientId]; - [result appendFormat:@", %@: %@", recipientId, NSStringForOutgoingMessageRecipientState(recipientState.state)]; - } - [result appendString:@"]"]; - return [result copy]; -} - @end NS_ASSUME_NONNULL_END