mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			207 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Objective-C
		
	
			
		
		
	
	
			207 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Objective-C
		
	
| #import "TSAttachmentPointer.h"
 | |
| #import "TSAttachmentStream.h"
 | |
| #import <SessionUtilitiesKit/MIMETypeUtil.h>
 | |
| #import <YapDatabase/YapDatabase.h>
 | |
| #import <YapDatabase/YapDatabaseTransaction.h>
 | |
| #import <SessionMessagingKit/SessionMessagingKit-Swift.h>
 | |
| 
 | |
| NS_ASSUME_NONNULL_BEGIN
 | |
| 
 | |
| @interface TSAttachmentStream (TSAttachmentPointer)
 | |
| 
 | |
| - (CGSize)cachedMediaSize;
 | |
| 
 | |
| @end
 | |
| 
 | |
| #pragma mark -
 | |
| 
 | |
| @implementation TSAttachmentPointer
 | |
| 
 | |
| - (nullable instancetype)initWithCoder:(NSCoder *)coder
 | |
| {
 | |
|     self = [super initWithCoder:coder];
 | |
|     if (!self) {
 | |
|         return self;
 | |
|     }
 | |
| 
 | |
|     // A TSAttachmentPointer is a yet-to-be-downloaded attachment.
 | |
|     // If this is an old TSAttachmentPointer from another session,
 | |
|     // we know that it failed to complete before the session completed.
 | |
|     if (![coder containsValueForKey:@"state"]) {
 | |
|         _state = TSAttachmentPointerStateFailed;
 | |
|     }
 | |
| 
 | |
|     if (_pointerType == TSAttachmentPointerTypeUnknown) {
 | |
|         _pointerType = TSAttachmentPointerTypeIncoming;
 | |
|     }
 | |
| 
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| - (instancetype)initWithServerId:(UInt64)serverId
 | |
|                              key:(nullable NSData *)key
 | |
|                           digest:(nullable NSData *)digest
 | |
|                        byteCount:(UInt32)byteCount
 | |
|                      contentType:(NSString *)contentType
 | |
|                   sourceFilename:(nullable NSString *)sourceFilename
 | |
|                          caption:(nullable NSString *)caption
 | |
|                   albumMessageId:(nullable NSString *)albumMessageId
 | |
|                   attachmentType:(TSAttachmentType)attachmentType
 | |
|                        mediaSize:(CGSize)mediaSize
 | |
| {
 | |
|     self = [super initWithServerId:serverId
 | |
|                      encryptionKey:key
 | |
|                          byteCount:byteCount
 | |
|                        contentType:contentType
 | |
|                     sourceFilename:sourceFilename
 | |
|                            caption:caption
 | |
|                     albumMessageId:albumMessageId];
 | |
|     if (!self) {
 | |
|         return self;
 | |
|     }
 | |
| 
 | |
|     _digest = digest;
 | |
|     _state = TSAttachmentPointerStateEnqueued;
 | |
|     self.attachmentType = attachmentType;
 | |
|     _pointerType = TSAttachmentPointerTypeIncoming;
 | |
|     _mediaSize = mediaSize;
 | |
| 
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| - (instancetype)initForRestoreWithAttachmentStream:(TSAttachmentStream *)attachmentStream
 | |
| {
 | |
|     self = [super initForRestoreWithUniqueId:attachmentStream.uniqueId
 | |
|                                  contentType:attachmentStream.contentType
 | |
|                               sourceFilename:attachmentStream.sourceFilename
 | |
|                                      caption:attachmentStream.caption
 | |
|                               albumMessageId:attachmentStream.albumMessageId];
 | |
|     if (!self) {
 | |
|         return self;
 | |
|     }
 | |
| 
 | |
|     _state = TSAttachmentPointerStateEnqueued;
 | |
|     self.attachmentType = attachmentStream.attachmentType;
 | |
|     _pointerType = TSAttachmentPointerTypeRestoring;
 | |
|     _mediaSize = (attachmentStream.shouldHaveImageSize ? attachmentStream.cachedMediaSize : CGSizeZero);
 | |
| 
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| + (nullable TSAttachmentPointer *)attachmentPointerFromProto:(SNProtoAttachmentPointer *)attachmentProto
 | |
|                                                 albumMessage:(nullable TSMessage *)albumMessage
 | |
| {
 | |
|     if (attachmentProto.id < 1) {
 | |
|         return nil;
 | |
|     }
 | |
| 
 | |
|     NSString *_Nullable fileName = attachmentProto.fileName;
 | |
|     NSString *_Nullable contentType = attachmentProto.contentType;
 | |
|     if (contentType.length < 1) {
 | |
|         // Content type might not set if the sending client can't
 | |
|         // infer a MIME type from the file extension.
 | |
|         NSString *_Nullable fileExtension = [fileName pathExtension].lowercaseString;
 | |
|         if (fileExtension.length > 0) {
 | |
|             contentType = [MIMETypeUtil mimeTypeForFileExtension:fileExtension];
 | |
|         }
 | |
|         if (contentType.length < 1) {
 | |
|             contentType = OWSMimeTypeApplicationOctetStream;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // digest will be empty for old clients.
 | |
|     NSData *_Nullable digest = attachmentProto.hasDigest ? attachmentProto.digest : nil;
 | |
| 
 | |
|     TSAttachmentType attachmentType = TSAttachmentTypeDefault;
 | |
|     if ([attachmentProto hasFlags]) {
 | |
|         UInt32 flags = attachmentProto.flags;
 | |
|         if ((flags & (UInt32)SNProtoAttachmentPointerFlagsVoiceMessage) > 0) {
 | |
|             attachmentType = TSAttachmentTypeVoiceMessage;
 | |
|         }
 | |
|     }
 | |
|     NSString *_Nullable caption;
 | |
|     if (attachmentProto.hasCaption) {
 | |
|         caption = attachmentProto.caption;
 | |
|     }
 | |
| 
 | |
|     CGSize mediaSize = CGSizeZero;
 | |
|     if (attachmentProto.hasWidth && attachmentProto.hasHeight && attachmentProto.width > 0
 | |
|         && attachmentProto.height > 0) {
 | |
|         mediaSize = CGSizeMake(attachmentProto.width, attachmentProto.height);
 | |
|     }
 | |
| 
 | |
|     TSAttachmentPointer *pointer = [[TSAttachmentPointer alloc] initWithServerId:attachmentProto.id
 | |
|                                                                              key:attachmentProto.key
 | |
|                                                                           digest:digest
 | |
|                                                                        byteCount:attachmentProto.size
 | |
|                                                                      contentType:contentType
 | |
|                                                                   sourceFilename:fileName
 | |
|                                                                          caption:caption
 | |
|                                                                   albumMessageId:0
 | |
|                                                                   attachmentType:attachmentType
 | |
|                                                                        mediaSize:mediaSize];
 | |
|     pointer.downloadURL = attachmentProto.url;
 | |
|     
 | |
|     return pointer;
 | |
| }
 | |
| 
 | |
| + (NSArray<TSAttachmentPointer *> *)attachmentPointersFromProtos:(NSArray<SNProtoAttachmentPointer *> *)attachmentProtos
 | |
|                                                     albumMessage:(TSMessage *)albumMessage
 | |
| {
 | |
|     NSMutableArray *attachmentPointers = [NSMutableArray new];
 | |
|     for (SNProtoAttachmentPointer *attachmentProto in attachmentProtos) {
 | |
|         TSAttachmentPointer *_Nullable attachmentPointer =
 | |
|             [self attachmentPointerFromProto:attachmentProto albumMessage:albumMessage];
 | |
|         if (attachmentPointer) {
 | |
|             [attachmentPointers addObject:attachmentPointer];
 | |
|         }
 | |
|     }
 | |
|     return [attachmentPointers copy];
 | |
| }
 | |
| 
 | |
| - (BOOL)isDecimalNumberText:(NSString *)text
 | |
| {
 | |
|     return [text componentsSeparatedByCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]].count == 1;
 | |
| }
 | |
| 
 | |
| - (void)upgradeFromAttachmentSchemaVersion:(NSUInteger)attachmentSchemaVersion
 | |
| {
 | |
|     // Legacy instances of TSAttachmentPointer apparently used the serverId as their
 | |
|     // uniqueId.
 | |
|     if (attachmentSchemaVersion < 2 && self.serverId == 0) {
 | |
|         if ([self isDecimalNumberText:self.uniqueId]) {
 | |
|             // For legacy instances, try to parse the serverId from the uniqueId.
 | |
|             self.serverId = (UInt64)[self.uniqueId integerValue];
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #pragma mark - Backups
 | |
| 
 | |
| - (nullable OWSBackupFragment *)lazyRestoreFragment
 | |
| {
 | |
|     if (!self.lazyRestoreFragmentId) {
 | |
|         return nil;
 | |
|     }
 | |
|     OWSBackupFragment *_Nullable backupFragment =
 | |
|         [OWSBackupFragment fetchObjectWithUniqueID:self.lazyRestoreFragmentId];
 | |
|     return backupFragment;
 | |
| }
 | |
| 
 | |
| - (void)markForLazyRestoreWithFragment:(OWSBackupFragment *)lazyRestoreFragment
 | |
|                            transaction:(YapDatabaseReadWriteTransaction *)transaction
 | |
| {
 | |
|     if (!lazyRestoreFragment.uniqueId) {
 | |
|         // If metadata hasn't been saved yet, save now.
 | |
|         [lazyRestoreFragment saveWithTransaction:transaction];
 | |
|     }
 | |
|     [self applyChangeToSelfAndLatestCopy:transaction
 | |
|                              changeBlock:^(TSAttachmentPointer *attachment) {
 | |
|                                  [attachment setLazyRestoreFragmentId:lazyRestoreFragment.uniqueId];
 | |
|                              }];
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| NS_ASSUME_NONNULL_END
 |