diff --git a/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift b/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift index 3c38759f8..79ef663a6 100644 --- a/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift +++ b/Signal/src/Jobs/ConversationConfigurationSyncOperation.swift @@ -89,6 +89,7 @@ class ConversationConfigurationSyncOperation: OWSOperation { contentType: OWSMimeTypeApplicationOctetStream, sourceFilename: nil, caption: nil, + albumMessageId: nil, isTemporaryAttachment: true) self.reportSuccess() } diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index b18f25bef..925746913 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -3760,6 +3760,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac contentType:@"audio/mp3" sourceFilename:@"test.mp3" caption:nil + albumMessageId:nil attachmentType:TSAttachmentTypeDefault]; pointer.state = TSAttachmentPointerStateFailed; [pointer saveWithTransaction:transaction]; @@ -3787,7 +3788,8 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" byteCount:filesize sourceFilename:filename - caption:nil]; + caption:nil + albumMessageId:nil]; NSError *error; BOOL success = [attachmentStream writeData:[self createRandomNSDataOfSize:filesize] error:&error]; @@ -4619,7 +4621,8 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:fakeAssetLoader.mimeType byteCount:nominalDataLength sourceFilename:filename - caption:nil]; + caption:nil + albumMessageId:nil]; NSError *error; BOOL success = [attachmentStream writeData:dataSource.data error:&error]; OWSAssertDebug(success && !error); @@ -4635,6 +4638,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac contentType:fakeAssetLoader.mimeType sourceFilename:fakeAssetLoader.filename caption:nil + albumMessageId:nil attachmentType:TSAttachmentTypeDefault]; attachmentPointer.state = TSAttachmentPointerStateFailed; [attachmentPointer saveWithTransaction:transaction]; diff --git a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m index 38d7e4327..bb0baad3c 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m @@ -119,6 +119,7 @@ NS_ASSUME_NONNULL_BEGIN contentType:OWSMimeTypeApplicationOctetStream sourceFilename:nil caption:nil + albumMessageId:nil isTemporaryAttachment:YES]; } diff --git a/SignalMessaging/attachments/SignalAttachment.swift b/SignalMessaging/attachments/SignalAttachment.swift index 6a645cc30..e8176968d 100644 --- a/SignalMessaging/attachments/SignalAttachment.swift +++ b/SignalMessaging/attachments/SignalAttachment.swift @@ -240,8 +240,13 @@ public class SignalAttachment: NSObject { } @objc - public var outgoingAttachmentInfo: OutgoingAttachmentInfo { - return OutgoingAttachmentInfo(dataSource: dataSource, contentType: mimeType, sourceFilename: filenameOrDefault, caption: captionText) + public func buildOutgoingAttachmentInfo(message: TSMessage) -> OutgoingAttachmentInfo { + OWSAssertDebug(message.uniqueId) + return OutgoingAttachmentInfo(dataSource: dataSource, + contentType: mimeType, + sourceFilename: filenameOrDefault, + caption: captionText, + albumMessageId: message.uniqueId) } @objc diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index cd4cab181..86e1b9287 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -133,7 +133,8 @@ NS_ASSUME_NONNULL_BEGIN NSMutableArray *attachmentInfos = [NSMutableArray new]; for (SignalAttachment *attachment in attachments) { - [attachmentInfos addObject:attachment.outgoingAttachmentInfo]; + OWSOutgoingAttachmentInfo *attachmentInfo = [attachment buildOutgoingAttachmentInfoWithMessage:message]; + [attachmentInfos addObject:attachmentInfo]; } [self.messageSenderJobQueue addMediaMessage:message attachmentInfos:attachmentInfos isTemporaryAttachment:NO]; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h index 926f65674..8bd3df862 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.h @@ -37,8 +37,12 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { // not the filename on disk. @property (nonatomic, readonly, nullable) NSString *sourceFilename; -// Currently only applies to albums. +#pragma mark - Media Album + @property (nonatomic, readonly, nullable) NSString *caption; +@property (nonatomic, readonly, nullable) NSString *albumMessageId; + +#pragma mark - // This constructor is used for new instances of TSAttachmentPointer, // i.e. undownloaded incoming attachments. @@ -47,14 +51,16 @@ typedef NS_ENUM(NSUInteger, TSAttachmentType) { byteCount:(UInt32)byteCount contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption; + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId; // This constructor is used for new instances of TSAttachmentStream // that represent new, un-uploaded outgoing attachments. - (instancetype)initWithContentType:(NSString *)contentType byteCount:(UInt32)byteCount sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption; + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId; // This constructor is used for new instances of TSAttachmentStream // that represent downloaded incoming attachments. diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m index 3e3786bfe..3f9e66824 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachment.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachment.m @@ -19,8 +19,6 @@ NSUInteger const TSAttachmentSchemaVersion = 4; @property (nonatomic) NSString *contentType; -@property (nonatomic, nullable) NSString *caption; - @end @implementation TSAttachment @@ -33,6 +31,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId { OWSAssertDebug(serverId > 0); OWSAssertDebug(encryptionKey.length > 0); @@ -70,6 +69,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; byteCount:(UInt32)byteCount sourceFilename:(nullable NSString *)sourceFilename caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId { if (contentType.length < 1) { OWSLogWarn(@"outgoing attachment has invalid content type"); @@ -88,6 +88,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; _byteCount = byteCount; _sourceFilename = sourceFilename; _caption = caption; + _albumMessageId = albumMessageId; _attachmentSchemaVersion = TSAttachmentSchemaVersion; @@ -229,19 +230,7 @@ NSUInteger const TSAttachmentSchemaVersion = 4; - (BOOL)isVisualMedia { - if (self.isImage) { - return YES; - } - - if (self.isVideo) { - return YES; - } - - if (self.isAnimated) { - return YES; - } - - return NO; + return [MIMETypeUtil isVisualMedia:self.contentType]; } - (nullable NSString *)sourceFilename diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h index 8fa4bfe67..01fedcdf3 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h @@ -28,6 +28,7 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) { contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER; + (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SSKProtoAttachmentPointer *)attachmentProto; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m index f851d8386..7af0bde9c 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m @@ -3,6 +3,7 @@ // #import "TSAttachmentPointer.h" +#import #import NS_ASSUME_NONNULL_BEGIN @@ -33,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId attachmentType:(TSAttachmentType)attachmentType { self = [super initWithServerId:serverId @@ -40,7 +42,8 @@ NS_ASSUME_NONNULL_BEGIN byteCount:byteCount contentType:contentType sourceFilename:sourceFilename - caption:caption]; + caption:caption + albumMessageId:albumMessageId]; if (!self) { return self; } @@ -54,6 +57,7 @@ NS_ASSUME_NONNULL_BEGIN + (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SSKProtoAttachmentPointer *)attachmentProto + message:(TSMessage *)message { if (attachmentProto.id < 1) { OWSFailDebug(@"Invalid attachment id."); @@ -82,6 +86,12 @@ NS_ASSUME_NONNULL_BEGIN if (attachmentProto.hasCaption) { caption = attachmentProto.caption; } + NSString *_Nullable albumMessageId; + if ([MIMETypeUtil isVisualMedia:attachmentProto.contentType]) { + OWSAssertDebug(message.uniqueId); + albumMessageId = message.uniqueId; + } + TSAttachmentPointer *pointer = [[TSAttachmentPointer alloc] initWithServerId:attachmentProto.id key:attachmentProto.key digest:digest @@ -89,6 +99,7 @@ NS_ASSUME_NONNULL_BEGIN contentType:attachmentProto.contentType sourceFilename:attachmentProto.fileName caption:caption + albumMessageId:albumMessageId attachmentType:attachmentType]; return pointer; } diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h index 37aab8fe8..1658f21bf 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h @@ -26,7 +26,8 @@ typedef void (^OWSThumbnailFailure)(void); - (instancetype)initWithContentType:(NSString *)contentType byteCount:(UInt32)byteCount sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption NS_DESIGNATED_INITIALIZER; + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId NS_DESIGNATED_INITIALIZER; - (instancetype)initWithPointer:(TSAttachmentPointer *)pointer NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index dac1abc76..c5e70b384 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -55,8 +55,13 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); byteCount:(UInt32)byteCount sourceFilename:(nullable NSString *)sourceFilename caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId { - self = [super initWithContentType:contentType byteCount:byteCount sourceFilename:sourceFilename caption:caption]; + self = [super initWithContentType:contentType + byteCount:byteCount + sourceFilename:sourceFilename + caption:caption + albumMessageId:albumMessageId]; if (!self) { return self; } @@ -856,7 +861,8 @@ typedef void (^OWSLoadedThumbnailSuccess)(OWSLoadedThumbnail *loadedThumbnail); [[TSAttachmentStream alloc] initWithContentType:OWSMimeTypeImageJpeg byteCount:(uint32_t)thumbnailData.length sourceFilename:thumbnailName - caption:nil]; + caption:nil + albumMessageId:nil]; NSError *error; BOOL success = [thumbnailAttachment writeData:thumbnailData error:&error]; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index b9e3b89b3..8a6ac2930 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -496,7 +496,8 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value) TSAttachmentStream *attachmentStream = [[TSAttachmentStream alloc] initWithContentType:OWSMimeTypeImageJpeg byteCount:(UInt32)imageData.length sourceFilename:nil - caption:nil]; + caption:nil + albumMessageId:nil]; NSError *error; BOOL success = [attachmentStream writeData:imageData error:&error]; diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 0b2fd266c..3cb39fa8e 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -904,6 +904,7 @@ NS_ASSUME_NONNULL_BEGIN contentType:OWSMimeTypeApplicationOctetStream sourceFilename:nil caption:nil + albumMessageId:nil isTemporaryAttachment:YES]; } else if (syncMessage.request.type == SSKProtoSyncMessageRequestTypeBlocked) { OWSLogInfo(@"Received request for block list"); @@ -1126,6 +1127,7 @@ NS_ASSUME_NONNULL_BEGIN contentType:OWSMimeTypeImagePng sourceFilename:nil caption:nil + albumMessageId:nil isTemporaryAttachment:YES]; } else { diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.h b/SignalServiceKit/src/Messages/OWSMessageSender.h index 043969a5c..76d6ac5bf 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.h +++ b/SignalServiceKit/src/Messages/OWSMessageSender.h @@ -40,13 +40,15 @@ NS_SWIFT_NAME(OutgoingAttachmentInfo) @property (nonatomic, readonly) NSString *contentType; @property (nonatomic, readonly, nullable) NSString *sourceFilename; @property (nonatomic, readonly, nullable) NSString *caption; +@property (nonatomic, readonly, nullable) NSString *albumMessageId; - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithDataSource:(DataSource *)dataSource contentType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename - caption:(nullable NSString *)caption NS_DESIGNATED_INITIALIZER; + caption:(nullable NSString *)caption + albumMessageId:(nullable NSString *)albumMessageId NS_DESIGNATED_INITIALIZER; @end diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index ec9cdc78a..6f955e33a 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1808,7 +1808,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [[TSAttachmentStream alloc] initWithContentType:attachmentInfo.contentType byteCount:(UInt32)attachmentInfo.dataSource.dataLength sourceFilename:attachmentInfo.sourceFilename - caption:attachmentInfo.caption]; + caption:attachmentInfo.caption + albumMessageId:attachmentInfo.albumMessageId]; if (outgoingMessage.isVoiceMessage) { attachmentStream.attachmentType = TSAttachmentTypeVoiceMessage; } diff --git a/SignalServiceKit/src/Network/MessageSenderJobQueue.swift b/SignalServiceKit/src/Network/MessageSenderJobQueue.swift index 5c36241db..8a96e1e3e 100644 --- a/SignalServiceKit/src/Network/MessageSenderJobQueue.swift +++ b/SignalServiceKit/src/Network/MessageSenderJobQueue.swift @@ -41,9 +41,9 @@ public class MessageSenderJobQueue: NSObject, JobQueue { self.add(message: message, removeMessageAfterSending: false, transaction: transaction) } - @objc(addMediaMessage:dataSource:contentType:sourceFilename:caption:isTemporaryAttachment:) - public func add(mediaMessage: TSOutgoingMessage, dataSource: DataSource, contentType: String, sourceFilename: String?, caption: String?, isTemporaryAttachment: Bool) { - let attachmentInfo = OutgoingAttachmentInfo(dataSource: dataSource, contentType: contentType, sourceFilename: sourceFilename, caption: caption) + @objc(addMediaMessage:dataSource:contentType:sourceFilename:caption:albumMessageId:isTemporaryAttachment:) + public func add(mediaMessage: TSOutgoingMessage, dataSource: DataSource, contentType: String, sourceFilename: String?, caption: String?, albumMessageId: String?, isTemporaryAttachment: Bool) { + let attachmentInfo = OutgoingAttachmentInfo(dataSource: dataSource, contentType: contentType, sourceFilename: sourceFilename, caption: caption, albumMessageId: albumMessageId) add(mediaMessage: mediaMessage, attachmentInfos: [attachmentInfo], isTemporaryAttachment: isTemporaryAttachment) } diff --git a/SignalServiceKit/src/Util/MIMETypeUtil.h b/SignalServiceKit/src/Util/MIMETypeUtil.h index 33b11b6d8..2c1063ad8 100644 --- a/SignalServiceKit/src/Util/MIMETypeUtil.h +++ b/SignalServiceKit/src/Util/MIMETypeUtil.h @@ -42,6 +42,7 @@ extern NSString *const kSyncMessageFileExtension; + (BOOL)isImage:(NSString *)contentType; + (BOOL)isVideo:(NSString *)contentType; + (BOOL)isAudio:(NSString *)contentType; ++ (BOOL)isVisualMedia:(NSString *)contentType; // filename is optional and should not be trusted. + (nullable NSString *)filePathForAttachment:(NSString *)uniqueId diff --git a/SignalServiceKit/src/Util/MIMETypeUtil.m b/SignalServiceKit/src/Util/MIMETypeUtil.m index 20d9d8a32..41b6f11e5 100644 --- a/SignalServiceKit/src/Util/MIMETypeUtil.m +++ b/SignalServiceKit/src/Util/MIMETypeUtil.m @@ -279,6 +279,23 @@ NSString *const kSyncMessageFileExtension = @"bin"; return [MIMETypeUtil isSupportedAudioMIMEType:contentType]; } ++ (BOOL)isVisualMedia:(NSString *)contentType +{ + if ([self isImage:contentType]) { + return YES; + } + + if ([self isVideo:contentType]) { + return YES; + } + + if ([self isAnimated:contentType]) { + return YES; + } + + return NO; +} + + (nullable NSString *)filePathForAttachment:(NSString *)uniqueId ofMIMEType:(NSString *)contentType sourceFilename:(nullable NSString *)sourceFilename