2018-11-21 01:38:43 -07:00
|
|
|
//
|
|
|
|
|
// MBIMFetchAttachmentOperation.m
|
|
|
|
|
// kordophoned
|
|
|
|
|
//
|
|
|
|
|
// Created by James Magahern on 11/20/18.
|
|
|
|
|
// Copyright © 2018 James Magahern. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#import "MBIMFetchAttachmentOperation.h"
|
|
|
|
|
#import "MBIMDataResponse.h"
|
2022-12-20 16:29:26 -08:00
|
|
|
#import "MBIMImageUtils.h"
|
2018-11-21 01:38:43 -07:00
|
|
|
|
2019-12-16 17:29:53 -08:00
|
|
|
#import "IMCore_ClassDump.h"
|
2022-12-20 16:29:26 -08:00
|
|
|
#import "IMSharedUtilities_ClassDump.h"
|
|
|
|
|
#import <CoreGraphics/CoreGraphics.h>
|
2018-11-21 01:38:43 -07:00
|
|
|
|
|
|
|
|
@implementation MBIMFetchAttachmentOperation
|
|
|
|
|
|
|
|
|
|
+ (void)load { [super load]; }
|
|
|
|
|
|
|
|
|
|
+ (NSString *)endpointName
|
|
|
|
|
{
|
|
|
|
|
return @"attachment";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)main
|
|
|
|
|
{
|
|
|
|
|
NSObject<HTTPResponse> *response = nil;
|
|
|
|
|
do {
|
2022-12-20 16:29:26 -08:00
|
|
|
BOOL preview = [[self valueForQueryItemWithName:@"preview"] boolValue];
|
2018-11-21 15:51:51 -07:00
|
|
|
NSString *guid = [self valueForQueryItemWithName:@"guid"];
|
2018-11-21 01:38:43 -07:00
|
|
|
if (!guid) {
|
2019-01-22 23:31:36 -08:00
|
|
|
MBIMLogInfo(@"No query item provided");
|
2018-11-21 01:38:43 -07:00
|
|
|
response = [[HTTPErrorResponse alloc] initWithErrorCode:500];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IMFileTransfer *transfer = [[IMFileTransferCenter sharedInstance] transferForGUID:guid];
|
|
|
|
|
if (!transfer) {
|
2019-01-22 23:31:36 -08:00
|
|
|
MBIMLogInfo(@"No transfer found for guid: %@", guid);
|
2018-11-21 01:38:43 -07:00
|
|
|
response = [[HTTPErrorResponse alloc] initWithErrorCode:404];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (![transfer existsAtLocalPath]) {
|
2019-01-22 23:31:36 -08:00
|
|
|
MBIMLogInfo(@"We don't have the file for this yet (still downloading to server?)");
|
2018-11-21 01:38:43 -07:00
|
|
|
response = [[HTTPErrorResponse alloc] initWithErrorCode:404];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-20 16:29:26 -08:00
|
|
|
NSData *responseData = nil;
|
|
|
|
|
NSURL *localURL = [transfer localURL];
|
|
|
|
|
NSString *extension = [[localURL pathExtension] lowercaseString];
|
|
|
|
|
if (preview) {
|
2024-01-07 18:11:59 -08:00
|
|
|
IMPreviewConstraints constraints = IMPreviewConstraintsZero();
|
|
|
|
|
|
|
|
|
|
// Fetch preview constraints from transfer
|
|
|
|
|
NSDictionary *previewConstraintsDict = [[transfer attributionInfo] objectForKey:@"pgenszc"];
|
|
|
|
|
if (previewConstraintsDict) {
|
|
|
|
|
constraints = IMPreviewConstraintsFromDictionary(previewConstraintsDict);
|
|
|
|
|
} else {
|
|
|
|
|
// Or, make a guess.
|
|
|
|
|
constraints.maxPxWidth = 500.0;
|
|
|
|
|
constraints.scale = 1.0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-20 16:29:26 -08:00
|
|
|
NSURL *previewURL = IMAttachmentPreviewFileURL(localURL, extension, YES);
|
2024-01-07 18:11:59 -08:00
|
|
|
if (!previewURL) {
|
|
|
|
|
// I'm not sure why this sometimes returns nil...
|
|
|
|
|
MBIMLogInfo(@"Unable to generate attachment preview cache URL for %@, making one up.", localURL);
|
|
|
|
|
|
|
|
|
|
NSURL *temporaryAttachmentCache = [[[NSFileManager defaultManager] temporaryDirectory] URLByAppendingPathComponent:@"kordophone_attachment_cache"];
|
|
|
|
|
temporaryAttachmentCache = [temporaryAttachmentCache URLByAppendingPathComponent:guid];
|
|
|
|
|
|
|
|
|
|
[[NSFileManager defaultManager] createDirectoryAtURL:temporaryAttachmentCache withIntermediateDirectories:YES attributes:nil error:nil];
|
|
|
|
|
|
|
|
|
|
previewURL = [temporaryAttachmentCache URLByAppendingPathComponent:[localURL lastPathComponent]];
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-20 16:29:26 -08:00
|
|
|
if (![[NSFileManager defaultManager] fileExistsAtPath:[previewURL path]]) {
|
|
|
|
|
MBIMLogInfo(@"Generating preview image for guid: %@ at %@", guid, [previewURL path]);
|
|
|
|
|
|
|
|
|
|
// Generate preview using preview generator manager
|
|
|
|
|
NSError *error = nil;
|
|
|
|
|
IMPreviewGeneratorManager *generator = [IMPreviewGeneratorManager sharedInstance];
|
|
|
|
|
CGImageRef previewImage = [generator newPreviewFromSourceURL:localURL withPreviewConstraints:constraints error:&error];
|
|
|
|
|
if (error) {
|
|
|
|
|
MBIMLogInfo(@"Unable to generate preview for attachment guid: %@", guid);
|
|
|
|
|
response = [[HTTPErrorResponse alloc] initWithErrorCode:500];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-20 16:43:45 -08:00
|
|
|
// Convert to JPEG.
|
2022-12-20 16:29:26 -08:00
|
|
|
responseData = MBIMCGImageJPEGRepresentation(previewImage);
|
|
|
|
|
|
|
|
|
|
// Persist JPEG preview to disk
|
2022-12-20 16:43:45 -08:00
|
|
|
if (previewURL) {
|
|
|
|
|
[responseData writeToURL:previewURL atomically:YES];
|
|
|
|
|
}
|
2022-12-20 16:29:26 -08:00
|
|
|
} else {
|
|
|
|
|
// File exists
|
|
|
|
|
MBIMLogInfo(@"Using cached preview image for guid: %@ at %@", guid, [previewURL path]);
|
|
|
|
|
responseData = [NSData dataWithContentsOfURL:previewURL];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
responseData = [NSData dataWithContentsOfURL:localURL];
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-21 01:38:43 -07:00
|
|
|
if (!responseData) {
|
2022-12-20 16:29:26 -08:00
|
|
|
MBIMLogInfo(@"Wasn't able to load data for guid: %@", guid);
|
2018-11-21 01:38:43 -07:00
|
|
|
response = [[HTTPErrorResponse alloc] initWithErrorCode:404];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSString *mimeType = [transfer mimeType];
|
2022-12-20 16:29:26 -08:00
|
|
|
if ([mimeType isEqualToString:@"image/heic"]) {
|
|
|
|
|
// TODO: We should convert this to JPEG here. I don't want clients to have to deal with HEIC.
|
|
|
|
|
MBIMLogInfo(@"WARNING: Returning HEIC data for attachment %@", guid);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-03 14:23:54 -08:00
|
|
|
// It's unusual, but if this is nil, try to guess the MIME type based on the filename
|
|
|
|
|
if (!mimeType) {
|
|
|
|
|
// XXX: REALLY hacky
|
|
|
|
|
mimeType = [NSString stringWithFormat:@"image/%@", extension];
|
|
|
|
|
}
|
2022-12-20 16:29:26 -08:00
|
|
|
|
2024-03-23 16:49:33 -07:00
|
|
|
MBIMDataResponse *dataResponse = [[MBIMDataResponse alloc] initWithData:responseData contentType:mimeType];
|
|
|
|
|
dataResponse.httpHeaders[@"Cache-Control"] = @"public, immutable, max-age=31536000";
|
|
|
|
|
response = dataResponse;
|
2018-11-21 01:38:43 -07:00
|
|
|
} while (0);
|
|
|
|
|
|
|
|
|
|
self.serverCompletionBlock(response);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|