// // DropboxV2ObjC.m // FMC Planner 2 // // Created by Kilian Hofmann on 29.03.16. // Copyright © 2016 Kilian Hofmann. All rights reserved. // #import "DropboxV2ObjC.h" @implementation DropboxV2ObjC - (DropboxV2ObjC *)init { self = [super init]; self.rootDirectory = @""; self.kJSONNullObject = [@"null" dataUsingEncoding:NSASCIIStringEncoding]; self.kDropboxProtectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"dropbox" port:443 protocol:@"HTTP" realm:nil authenticationMethod:@"OAuth2"]; return self; } #pragma mark - OAuth stuff // TODO: Alert on error - (BOOL)authorizeUserWithToke:(NSURL *)token completion:(void (^)(void))handler { NSScanner *scan = [NSScanner scannerWithString:token.absoluteString]; NSString *error = [[NSString alloc] init]; [scan scanUpToString:@"&error=" intoString:&error]; if (![error isEqualToString:token.absoluteString]) { handler(); return false; } // No error, refine token NSString *tokenUnrefined = [[NSString alloc] init]; scan = [NSScanner scannerWithString:token.absoluteString]; [scan scanUpToString:@"&" intoString:&tokenUnrefined]; NSString *tokenRefined = [tokenUnrefined substringFromIndex:21]; _token = tokenRefined; NSURLCredential *credential = [NSURLCredential credentialWithUser:@"Dropbox" password:_token persistence:NSURLCredentialPersistencePermanent]; [[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:_kDropboxProtectionSpace]; handler(); return true; } // TODO: Alert on error - (void)deauthorizeUser { NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; request.URL = [NSURL URLWithString:@"https://api.dropboxapi.com/1/disable_access_token"]; [request addValue:[NSString stringWithFormat:@"Bearer %@", _token] .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Authorization") .precomposedStringWithCanonicalMapping]; [request addValue:(@"application/json") .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Content-Type") .precomposedStringWithCanonicalMapping]; request.HTTPMethod = @"POST"; request.HTTPBody = _kJSONNullObject; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { if ([[NSJSONSerialization JSONObjectWithData:data options:0 error:nil] isEqualToDictionary:@{}]) { NSDictionary *credentials = [[NSURLCredentialStorage sharedCredentialStorage] credentialsForProtectionSpace: _kDropboxProtectionSpace]; NSURLCredential *credential = [credentials.objectEnumerator nextObject]; [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:credential forProtectionSpace:_kDropboxProtectionSpace]; } }]; } #pragma mark - File and directory operations /** * Pass nil as path for root dir * @return Content of directory at path or nil if error */ // !!!: Cannot be asynchronous // TODO: Alert on error - (NSArray *)contentsOfPath:(NSString *)path { if (path == nil) { path = _rootDirectory; } else { path = [path stringByAppendingString:[NSString stringWithFormat:@"/%@", path]]; } NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; request.URL = [NSURL URLWithString:@"https://api.dropboxapi.com/2/files/list_folder"]; [request addValue:[NSString stringWithFormat:@"Bearer %@", _token] .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Authorization") .precomposedStringWithCanonicalMapping]; [request addValue:(@"application/json") .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Content-Type") .precomposedStringWithCanonicalMapping]; request.HTTPMethod = @"POST"; NSData *data = [NSJSONSerialization dataWithJSONObject:@{ @"path" : path.precomposedStringWithCanonicalMapping } options:0 error:nil]; NSString *temp = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; temp = [temp stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"]; request.HTTPBody = [temp dataUsingEncoding:NSASCIIStringEncoding]; NSURLResponse *response = nil; NSError *error = nil; id dataOut = [self parseJSON:[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]]; if ([dataOut isKindOfClass:[NSDictionary class]]) { return [dataOut valueForKey:@"entries"]; } else { return nil; } } // TODO: Alert on error - (void)downloadFromDropbox:(NSArray *)files { NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; request.URL = [NSURL URLWithString:@"https://content.dropboxapi.com/2/files/download"]; [request addValue:[NSString stringWithFormat:@"Bearer %@", _token] .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Authorization") .precomposedStringWithCanonicalMapping]; [request addValue:(@"").precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Content-Type")]; request.HTTPMethod = @"POST"; request.HTTPBody = nil; // File Path for (NSString *string in files) { NSData *data = [NSJSONSerialization dataWithJSONObject:@{ @"path" : [NSString stringWithFormat:@"/%@", string] .precomposedStringWithCanonicalMapping } options:0 error:nil]; NSString *temp = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; temp = [temp stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"]; [request addValue:temp.precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Dropbox-API-Arg") .precomposedStringWithCanonicalMapping]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { if (error == nil) { [data writeToFile:[SharedDeclerations savePathForFile:string] atomically:YES]; } }]; } } // TODO: Alert on error - (void)uploadToDropbox:(NSArray *)files { NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; request.URL = [NSURL URLWithString:@"https://content.dropboxapi.com/2/files/upload"]; [request addValue:[NSString stringWithFormat:@"Bearer %@", _token] .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Authorization") .precomposedStringWithCanonicalMapping]; [request addValue:(@"application/octet-stream") .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Content-Type")]; request.HTTPMethod = @"POST"; // File Path for (NSString *string in files) { NSData *data = [NSJSONSerialization dataWithJSONObject:@{ @"path" : [NSString stringWithFormat:@"/%@", string] .precomposedStringWithCanonicalMapping, @"mode" : @"overwrite".precomposedStringWithCanonicalMapping, } options:0 error:nil]; NSString *temp = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; temp = [temp stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"]; [request addValue:temp.precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Dropbox-API-Arg") .precomposedStringWithCanonicalMapping]; request.HTTPBody = [NSData dataWithContentsOfFile:[SharedDeclerations savePathForFile:string]]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){ }]; } } #pragma mark - Other operations // !!!: Cannot be asynchronous // TODO: Alert on error - (NSDictionary *)getUserInfo { NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; request.URL = [NSURL URLWithString: @"https://api.dropboxapi.com/2/users/get_current_account"]; [request addValue:[NSString stringWithFormat:@"Bearer %@", _token] .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Authorization") .precomposedStringWithCanonicalMapping]; [request addValue:(@"application/json") .precomposedStringWithCanonicalMapping forHTTPHeaderField:(@"Content-Type") .precomposedStringWithCanonicalMapping]; request.HTTPMethod = @"POST"; request.HTTPBody = _kJSONNullObject; NSURLResponse *response = nil; NSError *error = nil; id data = [self parseJSON:[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]]; if ([data isKindOfClass:[NSDictionary class]]) { return data; } else { return nil; } } #pragma mark - Helper methods - (id)parseJSON:(NSData *)data { NSError *error = nil; id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (error == nil) { return object; } else { return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; } } @end