/* * 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 "TGAudioDownloadActor.h" #import "ActionStage.h" #import "TL/TLMetaScheme.h" #import "TGAudioMediaAttachment.h" #import "TGStringUtils.h" #import @implementation TGAudioDownloadActor + (void)load { [ASActor registerActorClass:self]; } - (instancetype)initWithPath:(NSString *)path { self = [super initWithPath:path]; if (self != nil) { _actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:false]; } return self; } - (void)dealloc { [_actionHandle reset]; [ActionStageInstance() removeWatcher:self]; } + (NSString *)genericPath { return @"/tg/media/audio/@"; } - (void)prepare:(NSDictionary *)options { [super prepare:options]; self.requestQueueName = @"documentDownload"; } - (void)execute:(NSDictionary *)options { TGAudioMediaAttachment *audioAttachment = options[@"audioAttachment"]; if (audioAttachment != nil) { TLInputFileLocation *inputFileLocation = nil; int datacenterId = 0; int encryptedSize = audioAttachment.fileSize; int decryptedSize = audioAttachment.fileSize; NSDictionary *encryptionArgs = @{}; NSString *storeAudioPathDirectory = nil; NSString *audioFilePath = nil; if (audioAttachment.audioId != 0) { storeAudioPathDirectory = [TGAudioMediaAttachment localAudioFileDirectoryForRemoteAudioId:audioAttachment.audioId]; audioFilePath = [TGAudioMediaAttachment localAudioFilePathForRemoteAudioId:audioAttachment.audioId]; } else { storeAudioPathDirectory = [TGAudioMediaAttachment localAudioFileDirectoryForLocalAudioId:audioAttachment.localAudioId]; audioFilePath = [TGAudioMediaAttachment localAudioFilePathForLocalAudioId:audioAttachment.localAudioId]; } [[NSFileManager defaultManager] createDirectoryAtPath:storeAudioPathDirectory withIntermediateDirectories:true attributes:nil error:nil]; // NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:audioFilePath error:nil]; if (audioAttachment.audioUri.length != 0) { if ([audioAttachment.audioUri hasPrefix:@"mt-encrypted-file://"]) { NSDictionary *args = [TGStringUtils argumentDictionaryInUrlString:[audioAttachment.audioUri 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 = audioAttachment.audioId; inputDocumentLocation.access_hash = audioAttachment.accessHash; inputFileLocation = inputDocumentLocation; datacenterId = audioAttachment.datacenterId; } if (inputFileLocation != nil) { [ActionStageInstance() requestActor:[[NSString alloc] initWithFormat:@"/tg/multipart-file/(audio:%" PRId64 ":%d:%@)", audioAttachment.audioId, audioAttachment.datacenterId, audioAttachment.audioUri.length != 0 ? audioAttachment.audioUri : @""] options:@{ @"fileLocation": inputFileLocation, @"encryptedSize": @(encryptedSize), @"decryptedSize": @(decryptedSize), @"storeFilePath": audioFilePath, @"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]; [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]; } } } - (void)actorCompleted:(int)status path:(NSString *)path result:(id)__unused result { if ([path hasPrefix:@"/tg/multipart-file/"]) { if (status == ASStatusSuccess) { [ActionStageInstance() actionCompleted:self.path result:nil]; } else { [ActionStageInstance() actionFailed:self.path reason:-1]; } } } @end