mirror of
https://github.com/danog/Telegram.git
synced 2024-12-02 09:27:55 +01:00
258 lines
8.7 KiB
Objective-C
258 lines
8.7 KiB
Objective-C
/*
|
|
* This is the source code of Telegram for iOS v. 1.1
|
|
* It is licensed under GNU GPL v. 2 or later.
|
|
* You should have received a copy of the license in this archive (see LICENSE).
|
|
*
|
|
* Copyright Peter Iakovlev, 2013.
|
|
*/
|
|
|
|
#import "TGDocumentDownloadActor.h"
|
|
|
|
#import "ActionStage.h"
|
|
#import "ASQueue.h"
|
|
|
|
#import "TL/TLMetaScheme.h"
|
|
#import "TGDocumentMediaAttachment.h"
|
|
|
|
#import "TGStringUtils.h"
|
|
#import "TGImageUtils.h"
|
|
#import "TGRemoteImageView.h"
|
|
|
|
#import "TGGenericModernConversationCompanion.h"
|
|
#import "TGFileDownloadActor.h"
|
|
|
|
#import <CommonCrypto/CommonDigest.h>
|
|
|
|
#import "TGAppDelegate.h"
|
|
|
|
#import "TGDocumentHttpFileReference.h"
|
|
#import "PSKeyValueDecoder.h"
|
|
|
|
#import "TGRemoteHttpLocationSignal.h"
|
|
|
|
@interface TGDocumentDownloadActor ()
|
|
{
|
|
TGDocumentMediaAttachment *_documentAttachment;
|
|
NSString *_storeFilePath;
|
|
SDisposableSet *_disposables;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation TGDocumentDownloadActor
|
|
|
|
- (instancetype)initWithPath:(NSString *)path
|
|
{
|
|
self = [super initWithPath:path];
|
|
if (self != nil)
|
|
{
|
|
_actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:false];
|
|
_disposables = [[SDisposableSet alloc] init];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[_actionHandle reset];
|
|
[ActionStageInstance() removeWatcher:self];
|
|
[_disposables dispose];
|
|
}
|
|
|
|
+ (NSString *)genericPath
|
|
{
|
|
return @"/tg/media/document/@";
|
|
}
|
|
|
|
- (void)prepare:(NSDictionary *)options
|
|
{
|
|
[super prepare:options];
|
|
|
|
self.requestQueueName = @"documentDownload";
|
|
}
|
|
|
|
- (void)execute:(NSDictionary *)options
|
|
{
|
|
TGDocumentMediaAttachment *documentAttachment = options[@"documentAttachment"];
|
|
_documentAttachment = documentAttachment;
|
|
|
|
if (documentAttachment != nil)
|
|
{
|
|
TLInputFileLocation *inputFileLocation = nil;
|
|
int datacenterId = 0;
|
|
int encryptedSize = documentAttachment.size;
|
|
int decryptedSize = documentAttachment.size;
|
|
NSDictionary *encryptionArgs = @{};
|
|
|
|
NSString *documentsDirectory = [TGAppDelegate documentsPath];
|
|
NSString *currentDocumentDirectory = nil;
|
|
if (documentAttachment.documentId != 0)
|
|
{
|
|
currentDocumentDirectory = [[documentsDirectory stringByAppendingPathComponent:@"files"] stringByAppendingPathComponent:[[NSString alloc] initWithFormat:@"%" PRIx64 "", documentAttachment.documentId]];
|
|
}
|
|
else
|
|
{
|
|
currentDocumentDirectory = [[documentsDirectory stringByAppendingPathComponent:@"files"] stringByAppendingPathComponent:[[NSString alloc] initWithFormat:@"local%" PRIx64 "", documentAttachment.localDocumentId]];
|
|
}
|
|
|
|
if (![[NSFileManager defaultManager] fileExistsAtPath:currentDocumentDirectory])
|
|
[[NSFileManager defaultManager] createDirectoryAtPath:currentDocumentDirectory withIntermediateDirectories:true attributes:nil error:nil];
|
|
|
|
_storeFilePath = [currentDocumentDirectory stringByAppendingPathComponent:documentAttachment.safeFileName];
|
|
|
|
if (documentAttachment.documentUri.length != 0)
|
|
{
|
|
if ([documentAttachment.documentUri hasPrefix:@"mt-encrypted-file://"])
|
|
{
|
|
NSDictionary *args = [TGStringUtils argumentDictionaryInUrlString:[documentAttachment.documentUri substringFromIndex:@"mt-encrypted-file://?".length]];
|
|
|
|
NSData *key = [args[@"key"] dataByDecodingHexString];
|
|
|
|
if (key.length != 64)
|
|
TGLog(@"***** Invalid file key length");
|
|
else
|
|
{
|
|
NSData *encryptionKey = [key subdataWithRange:NSMakeRange(0, 32)];
|
|
NSData *encryptionIv = [key subdataWithRange:NSMakeRange(32, 32)];
|
|
|
|
unsigned char digest[CC_MD5_DIGEST_LENGTH];
|
|
CC_MD5(key.bytes, 32 + 32, digest);
|
|
|
|
int32_t digestHigh = 0;
|
|
int32_t digestLow = 0;
|
|
memcpy(&digestHigh, digest, 4);
|
|
memcpy(&digestLow, digest + 4, 4);
|
|
|
|
int32_t key_fingerprint = digestHigh ^ digestLow;
|
|
if (args[@"fingerprint"] != nil && [args[@"fingerprint"] intValue] != key_fingerprint)
|
|
TGLog(@"***** Invalid file key fingerprint");
|
|
else
|
|
{
|
|
TLInputFileLocation$inputEncryptedFileLocation *inputEncryptedLocation = [[TLInputFileLocation$inputEncryptedFileLocation alloc] init];
|
|
inputEncryptedLocation.n_id = [args[@"id"] longLongValue];
|
|
inputEncryptedLocation.access_hash = [args[@"accessHash"] longLongValue];
|
|
inputFileLocation = inputEncryptedLocation;
|
|
|
|
datacenterId = [args[@"dc"] intValue];
|
|
encryptedSize = [args[@"size"] intValue];
|
|
decryptedSize = [args[@"decryptedSize"] intValue];
|
|
|
|
encryptionArgs = @{@"key": encryptionKey, @"iv": encryptionIv};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TLInputFileLocation$inputDocumentFileLocation *inputDocumentLocation = [[TLInputFileLocation$inputDocumentFileLocation alloc] init];
|
|
inputDocumentLocation.n_id = documentAttachment.documentId;
|
|
inputDocumentLocation.access_hash = documentAttachment.accessHash;
|
|
inputFileLocation = inputDocumentLocation;
|
|
|
|
datacenterId = documentAttachment.datacenterId;
|
|
}
|
|
|
|
if (inputFileLocation != nil)
|
|
{
|
|
[ActionStageInstance() requestActor:[[NSString alloc] initWithFormat:@"/tg/multipart-file/(document:%" PRId64 ":%d:%@)", documentAttachment.documentId, documentAttachment.datacenterId, documentAttachment.documentUri.length != 0 ? documentAttachment.documentUri : @""] options:@{
|
|
@"fileLocation": inputFileLocation,
|
|
@"encryptedSize": @(encryptedSize),
|
|
@"decryptedSize": @(decryptedSize),
|
|
@"storeFilePath": _storeFilePath,
|
|
@"datacenterId": @(datacenterId),
|
|
@"encryptionArgs": encryptionArgs
|
|
} watcher:self];
|
|
}
|
|
else
|
|
[ActionStageInstance() actionFailed:self.path reason:-1];
|
|
}
|
|
else
|
|
{
|
|
[ActionStageInstance() actionFailed:self.path reason:-1];
|
|
}
|
|
}
|
|
|
|
- (void)cancel
|
|
{
|
|
[ActionStageInstance() removeWatcher:self];
|
|
|
|
[_disposables dispose];
|
|
|
|
[super cancel];
|
|
}
|
|
|
|
- (void)actorMessageReceived:(NSString *)path messageType:(NSString *)messageType message:(id)message
|
|
{
|
|
if ([path hasPrefix:@"/tg/multipart-file/"])
|
|
{
|
|
if ([messageType isEqualToString:@"progress"])
|
|
{
|
|
[ActionStageInstance() dispatchMessageToWatchers:self.path messageType:messageType message:message];
|
|
}
|
|
}
|
|
}
|
|
|
|
+ (ASQueue *)previewGenerationQueue
|
|
{
|
|
static ASQueue *queue = nil;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^
|
|
{
|
|
queue = [[ASQueue alloc] initWithName:"org.telegram.documentDownloadPreviewGeneration"];
|
|
});
|
|
|
|
return queue;
|
|
}
|
|
|
|
- (bool)fileIsImage
|
|
{
|
|
NSArray *imageFileExtensions = @[@"gif", @"png", @"jpg", @"jpeg"];
|
|
NSArray *imageMimeTypes = @[@"image/gif"];
|
|
|
|
NSString *extension = [_documentAttachment.fileName pathExtension];
|
|
for (NSString *sampleExtension in imageFileExtensions)
|
|
{
|
|
if ([[extension lowercaseString] isEqualToString:sampleExtension])
|
|
return true;
|
|
}
|
|
|
|
for (NSString *sampleMimeType in imageMimeTypes)
|
|
{
|
|
if ([_documentAttachment.mimeType isEqualToString:sampleMimeType])
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
- (void)actorCompleted:(int)status path:(NSString *)path result:(id)__unused result
|
|
{
|
|
if ([path hasPrefix:@"/tg/multipart-file/"])
|
|
{
|
|
if (status == ASStatusSuccess)
|
|
{
|
|
NSString *thumbnailUri = [_documentAttachment.thumbnailInfo imageUrlForLargestSize:NULL];
|
|
|
|
if (thumbnailUri != nil)
|
|
{
|
|
//bool isImage = [self fileIsImage];
|
|
|
|
[ActionStageInstance() actionCompleted:self.path result:nil];
|
|
|
|
//if (isImage)
|
|
{
|
|
[ActionStageInstance() dispatchResource:[[NSString alloc] initWithFormat:@"/as/media/imageThumbnailUpdated"] resource:thumbnailUri];
|
|
}
|
|
}
|
|
else
|
|
[ActionStageInstance() actionCompleted:self.path result:nil];
|
|
}
|
|
else
|
|
{
|
|
[ActionStageInstance() actionFailed:self.path reason:-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
@end
|