diff --git a/Classes/DropboxAPIKeys.h b/Classes/DropboxAPIKeys.h new file mode 100644 index 0000000..a222671 --- /dev/null +++ b/Classes/DropboxAPIKeys.h @@ -0,0 +1,10 @@ +// +// DropboxAPIKeys.h +// MyKeePass +// +// Created by Jose Ramon Roca on 08/05/11. +// Copyright 2011 -. All rights reserved. +// + +#define DROPBOX_CONSUMER_KEY "" +#define DROPBOX_CONSUMER_SECRET "" \ No newline at end of file diff --git a/Classes/MyKeePassAppDelegate.h b/Classes/MyKeePassAppDelegate.h index bcd04d1..5c20d6d 100644 --- a/Classes/MyKeePassAppDelegate.h +++ b/Classes/MyKeePassAppDelegate.h @@ -2,25 +2,38 @@ // MyKeePassAppDelegate.h // MyKeePass // -// Created by Qiang Yu on 12/4/09. -// Copyright __MyCompanyName__ 2009. All rights reserved. +// Created by Qiang Yu on 3/3/10. +// Copyright Qiang Yu 2010. All rights reserved. // #import #import "MainViewController.h" -#import "DatabaseWrapper.h" +#import "KdbViewController.h" +#import "PasswordViewController.h" +#import "FileManager.h" @interface MyKeePassAppDelegate : NSObject { - UIWindow *window; - MainViewController * _mainViewController; - DatabaseWrapper * _databaseWrapper; + FileManager * _fileManager; + + MainViewController * _mainView; + KdbViewController * _kdbView; + + UIViewController * _currentViewController; + + UIWindow *window; } @property (nonatomic, retain) IBOutlet UIWindow *window; -@property (nonatomic, retain) IBOutlet MainViewController * _mainViewController; -@property(nonatomic, retain) DatabaseWrapper * _databaseWrapper; +@property (nonatomic, readonly) FileManager * _fileManager; +@property (nonatomic, retain) MainViewController * _mainView; +@property (nonatomic, retain) KdbViewController * _kdbView; +@property (nonatomic, retain) UIViewController * _currentViewController; --(void)switchViews; ++(MyKeePassAppDelegate *)delegate; ++(UIWindow *)getWindow; +-(void)showKdb; +-(void)showMainView; +-(BOOL)isEditable; @end diff --git a/Classes/MyKeePassAppDelegate.m b/Classes/MyKeePassAppDelegate.m index e5205b8..2071f95 100644 --- a/Classes/MyKeePassAppDelegate.m +++ b/Classes/MyKeePassAppDelegate.m @@ -2,63 +2,115 @@ // MyKeePassAppDelegate.m // MyKeePass // -// Created by Qiang Yu on 12/4/09. -// Copyright __MyCompanyName__ 2009. All rights reserved. +// Created by Qiang Yu on 3/3/10. +// Copyright Qiang Yu 2010. All rights reserved. // +#import #import "MyKeePassAppDelegate.h" +#import "DropboxSDK.h" +#import "DropboxAPIKeys.h" @implementation MyKeePassAppDelegate - @synthesize window; -@synthesize _mainViewController; -@synthesize _databaseWrapper; - --(id)init{ - if(self==[super init]){ - self._databaseWrapper = [[DatabaseWrapper alloc]init]; - } - return self; -} +@synthesize _fileManager; +@synthesize _kdbView; +@synthesize _mainView; +@synthesize _currentViewController; - (void)applicationDidFinishLaunching:(UIApplication *)application { - [window addSubview:_mainViewController.view]; - // Override point for customization after application launch + DBSession* dbSession = [[[DBSession alloc] + initWithConsumerKey:@DROPBOX_CONSUMER_KEY + consumerSecret:@DROPBOX_CONSUMER_SECRET] + autorelease]; + [DBSession setSharedSession:dbSession]; + + //initialize the file manager + _fileManager = [[FileManager alloc]init]; + + //initialize the main view + _mainView = [[MainViewController alloc]init]; + + self._currentViewController = _mainView; + + [window addSubview:_mainView.view]; [window makeKeyAndVisible]; } - (void)dealloc { + [_mainView release]; + [_kdbView release]; [window release]; - [_mainViewController release]; - [_databaseWrapper release]; + [_fileManager release]; + [_currentViewController release]; [super dealloc]; } - --(void)switchViews{ - [_mainViewController switchViews]; +-(void)showKdb{ + if(![_currentViewController isKindOfClass:[KdbViewController class]]){ + [_currentViewController.view removeFromSuperview]; + id kdbReader = _fileManager._kdbReader; + + if(!_kdbView){ + _kdbView = [[KdbViewController alloc]initWithGroup:[[kdbReader getKdbTree] getRoot]]; + } + + self._currentViewController = _kdbView; + + [window addSubview:_currentViewController.view]; + + CATransition *animation = [CATransition animation]; + [animation setDuration:0.5]; + [animation setType:kCATransitionFade]; + [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; + [[window layer] addAnimation:animation forKey:@"SwitchToKdbView"]; + } } -- (void)applicationWillResignActive:(UIApplication *)application{ - //clean views e.g. dismiss modal views such as TableTextFieldEditViewController - [_mainViewController cleanViews]; - [_databaseWrapper saveDatabase]; - _databaseWrapper._database = nil; +-(void)showMainView{ + if(![_currentViewController isKindOfClass:[MainViewController class]]){ + [_currentViewController.view removeFromSuperview]; + _fileManager._kdbReader = nil; + self._kdbView = nil; + + if(!_mainView) + _mainView = [[MainViewController alloc]init]; + + self._currentViewController = _mainView; + + [window addSubview:_currentViewController.view]; + + CATransition *animation = [CATransition animation]; + [animation setDuration:0.5]; + [animation setType:kCATransitionFade]; + [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; + [[window layer] addAnimation:animation forKey:@"SwitchToMainView"]; + } } - (void)applicationDidBecomeActive:(UIApplication *)application{ - /// - //switch the view to fileview whenever the application becomes active - /// - if(!_mainViewController._fileViewController.view.superview){ - [self switchViews]; + if([_currentViewController isKindOfClass:[KdbViewController class]]){ + [_currentViewController.view removeFromSuperview]; + + PasswordViewController * lockWindow = [[PasswordViewController alloc] initWithFileName:_fileManager._filename remote:NO]; + lockWindow._isReopen = YES; + + self._currentViewController = lockWindow; + [window addSubview:lockWindow.view]; + [lockWindow release]; } } -- (void)applicationWillTerminate:(UIApplication *)application{ - [_databaseWrapper saveDatabase]; +-(BOOL)isEditable{ + return _fileManager._editable; } ++(MyKeePassAppDelegate *)delegate{ + return (MyKeePassAppDelegate *)[[UIApplication sharedApplication] delegate]; +} ++(UIWindow *)getWindow{ + return ((MyKeePassAppDelegate *)[[UIApplication sharedApplication] delegate]).window; +} @end diff --git a/ASIAuthenticationDialog.h b/Classes/ThirdParty/ASIHTTPRequest/ASIAuthenticationDialog.h similarity index 100% rename from ASIAuthenticationDialog.h rename to Classes/ThirdParty/ASIHTTPRequest/ASIAuthenticationDialog.h diff --git a/ASIAuthenticationDialog.m b/Classes/ThirdParty/ASIHTTPRequest/ASIAuthenticationDialog.m similarity index 100% rename from ASIAuthenticationDialog.m rename to Classes/ThirdParty/ASIHTTPRequest/ASIAuthenticationDialog.m diff --git a/ASIFormDataRequest.h b/Classes/ThirdParty/ASIHTTPRequest/ASIFormDataRequest.h similarity index 100% rename from ASIFormDataRequest.h rename to Classes/ThirdParty/ASIHTTPRequest/ASIFormDataRequest.h diff --git a/ASIFormDataRequest.m b/Classes/ThirdParty/ASIHTTPRequest/ASIFormDataRequest.m similarity index 100% rename from ASIFormDataRequest.m rename to Classes/ThirdParty/ASIHTTPRequest/ASIFormDataRequest.m diff --git a/ASIHTTPRequest.h b/Classes/ThirdParty/ASIHTTPRequest/ASIHTTPRequest.h similarity index 100% rename from ASIHTTPRequest.h rename to Classes/ThirdParty/ASIHTTPRequest/ASIHTTPRequest.h diff --git a/ASIHTTPRequest.m b/Classes/ThirdParty/ASIHTTPRequest/ASIHTTPRequest.m similarity index 100% rename from ASIHTTPRequest.m rename to Classes/ThirdParty/ASIHTTPRequest/ASIHTTPRequest.m diff --git a/ASIHTTPRequestConfig.h b/Classes/ThirdParty/ASIHTTPRequest/ASIHTTPRequestConfig.h similarity index 100% rename from ASIHTTPRequestConfig.h rename to Classes/ThirdParty/ASIHTTPRequest/ASIHTTPRequestConfig.h diff --git a/ASIInputStream.h b/Classes/ThirdParty/ASIHTTPRequest/ASIInputStream.h similarity index 100% rename from ASIInputStream.h rename to Classes/ThirdParty/ASIHTTPRequest/ASIInputStream.h diff --git a/ASIInputStream.m b/Classes/ThirdParty/ASIHTTPRequest/ASIInputStream.m similarity index 100% rename from ASIInputStream.m rename to Classes/ThirdParty/ASIHTTPRequest/ASIInputStream.m diff --git a/ASINSStringAdditions.h b/Classes/ThirdParty/ASIHTTPRequest/ASINSStringAdditions.h similarity index 100% rename from ASINSStringAdditions.h rename to Classes/ThirdParty/ASIHTTPRequest/ASINSStringAdditions.h diff --git a/ASINSStringAdditions.m b/Classes/ThirdParty/ASIHTTPRequest/ASINSStringAdditions.m similarity index 100% rename from ASINSStringAdditions.m rename to Classes/ThirdParty/ASIHTTPRequest/ASINSStringAdditions.m diff --git a/ASINetworkQueue.h b/Classes/ThirdParty/ASIHTTPRequest/ASINetworkQueue.h similarity index 100% rename from ASINetworkQueue.h rename to Classes/ThirdParty/ASIHTTPRequest/ASINetworkQueue.h diff --git a/ASINetworkQueue.m b/Classes/ThirdParty/ASIHTTPRequest/ASINetworkQueue.m similarity index 100% rename from ASINetworkQueue.m rename to Classes/ThirdParty/ASIHTTPRequest/ASINetworkQueue.m diff --git a/Reachability.h b/Classes/ThirdParty/ASIHTTPRequest/Reachability.h similarity index 100% rename from Reachability.h rename to Classes/ThirdParty/ASIHTTPRequest/Reachability.h diff --git a/Reachability.m b/Classes/ThirdParty/ASIHTTPRequest/Reachability.m similarity index 100% rename from Reachability.m rename to Classes/ThirdParty/ASIHTTPRequest/Reachability.m diff --git a/DDData.h b/Classes/ThirdParty/CocoaHttpServer/Categories/DDData.h similarity index 100% rename from DDData.h rename to Classes/ThirdParty/CocoaHttpServer/Categories/DDData.h diff --git a/DDData.m b/Classes/ThirdParty/CocoaHttpServer/Categories/DDData.m similarity index 100% rename from DDData.m rename to Classes/ThirdParty/CocoaHttpServer/Categories/DDData.m diff --git a/DDNumber.h b/Classes/ThirdParty/CocoaHttpServer/Categories/DDNumber.h similarity index 100% rename from DDNumber.h rename to Classes/ThirdParty/CocoaHttpServer/Categories/DDNumber.h diff --git a/DDNumber.m b/Classes/ThirdParty/CocoaHttpServer/Categories/DDNumber.m similarity index 100% rename from DDNumber.m rename to Classes/ThirdParty/CocoaHttpServer/Categories/DDNumber.m diff --git a/DDRange.h b/Classes/ThirdParty/CocoaHttpServer/Categories/DDRange.h similarity index 100% rename from DDRange.h rename to Classes/ThirdParty/CocoaHttpServer/Categories/DDRange.h diff --git a/DDRange.m b/Classes/ThirdParty/CocoaHttpServer/Categories/DDRange.m similarity index 100% rename from DDRange.m rename to Classes/ThirdParty/CocoaHttpServer/Categories/DDRange.m diff --git a/MyHTTPConnection.h b/Classes/ThirdParty/CocoaHttpServer/Classes/MyHTTPConnection.h similarity index 100% rename from MyHTTPConnection.h rename to Classes/ThirdParty/CocoaHttpServer/Classes/MyHTTPConnection.h diff --git a/MyHTTPConnection.m b/Classes/ThirdParty/CocoaHttpServer/Classes/MyHTTPConnection.m similarity index 100% rename from MyHTTPConnection.m rename to Classes/ThirdParty/CocoaHttpServer/Classes/MyHTTPConnection.m diff --git a/localhostAddresses.h b/Classes/ThirdParty/CocoaHttpServer/Classes/localhostAddresses.h similarity index 100% rename from localhostAddresses.h rename to Classes/ThirdParty/CocoaHttpServer/Classes/localhostAddresses.h diff --git a/localhostAddresses.m b/Classes/ThirdParty/CocoaHttpServer/Classes/localhostAddresses.m similarity index 100% rename from localhostAddresses.m rename to Classes/ThirdParty/CocoaHttpServer/Classes/localhostAddresses.m diff --git a/HTTPAuthenticationRequest.h b/Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPAuthenticationRequest.h similarity index 100% rename from HTTPAuthenticationRequest.h rename to Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPAuthenticationRequest.h diff --git a/HTTPAuthenticationRequest.m b/Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPAuthenticationRequest.m similarity index 100% rename from HTTPAuthenticationRequest.m rename to Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPAuthenticationRequest.m diff --git a/HTTPConnection.h b/Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPConnection.h similarity index 100% rename from HTTPConnection.h rename to Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPConnection.h diff --git a/HTTPConnection.m b/Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPConnection.m similarity index 100% rename from HTTPConnection.m rename to Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPConnection.m diff --git a/HTTPResponse.h b/Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPResponse.h similarity index 100% rename from HTTPResponse.h rename to Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPResponse.h diff --git a/HTTPResponse.m b/Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPResponse.m similarity index 100% rename from HTTPResponse.m rename to Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPResponse.m diff --git a/HTTPServer.h b/Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPServer.h similarity index 100% rename from HTTPServer.h rename to Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPServer.h diff --git a/HTTPServer.m b/Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPServer.m similarity index 100% rename from HTTPServer.m rename to Classes/ThirdParty/CocoaHttpServer/HTTP/HTTPServer.m diff --git a/AsyncSocket.h b/Classes/ThirdParty/CocoaHttpServer/TCP/AsyncSocket.h similarity index 100% rename from AsyncSocket.h rename to Classes/ThirdParty/CocoaHttpServer/TCP/AsyncSocket.h diff --git a/AsyncSocket.m b/Classes/ThirdParty/CocoaHttpServer/TCP/AsyncSocket.m similarity index 100% rename from AsyncSocket.m rename to Classes/ThirdParty/CocoaHttpServer/TCP/AsyncSocket.m diff --git a/Classes/ThirdParty/DropboxSDK/DBAccountInfo.h b/Classes/ThirdParty/DropboxSDK/DBAccountInfo.h new file mode 100644 index 0000000..e54d544 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBAccountInfo.h @@ -0,0 +1,28 @@ +// +// DBAccountInfo.h +// DropboxSDK +// +// Created by Brian Smith on 5/3/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + + +#import "DBQuota.h" + +@interface DBAccountInfo : NSObject { + NSString* country; + NSString* displayName; + DBQuota* quota; + NSString* userId; + NSString* referralLink; +} + +- (id)initWithDictionary:(NSDictionary*)dict; + +@property (nonatomic, readonly) NSString* country; +@property (nonatomic, readonly) NSString* displayName; +@property (nonatomic, readonly) DBQuota* quota; +@property (nonatomic, readonly) NSString* userId; +@property (nonatomic, readonly) NSString* referralLink; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBAccountInfo.m b/Classes/ThirdParty/DropboxSDK/DBAccountInfo.m new file mode 100644 index 0000000..e30ffbc --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBAccountInfo.m @@ -0,0 +1,61 @@ +// +// DBAccountInfo.m +// DropboxSDK +// +// Created by Brian Smith on 5/3/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBAccountInfo.h" + + +@implementation DBAccountInfo + +- (id)initWithDictionary:(NSDictionary*)dict { + if ((self = [super init])) { + country = [[dict objectForKey:@"country"] retain]; + displayName = [[dict objectForKey:@"display_name"] retain]; + quota = [[DBQuota alloc] initWithDictionary:[dict objectForKey:@"quota_info"]]; + userId = [[[dict objectForKey:@"uid"] stringValue] retain]; + referralLink = [[dict objectForKey:@"referral_link"] retain]; + } + return self; +} + +- (void)dealloc { + [country release]; + [displayName release]; + [quota release]; + [userId release]; + [referralLink release]; + [super dealloc]; +} + +@synthesize country; +@synthesize displayName; +@synthesize quota; +@synthesize userId; +@synthesize referralLink; + + +#pragma mark NSCoding methods + +- (void)encodeWithCoder:(NSCoder*)coder { + [coder encodeObject:country forKey:@"country"]; + [coder encodeObject:displayName forKey:@"displayName"]; + [coder encodeObject:quota forKey:@"quota"]; + [coder encodeObject:userId forKey:@"userId"]; + [coder encodeObject:referralLink forKey:@"referralLink"]; +} + +- (id)initWithCoder:(NSCoder*)coder { + self = [super init]; + country = [[coder decodeObjectForKey:@"country"] retain]; + displayName = [[coder decodeObjectForKey:@"displayName"] retain]; + quota = [[coder decodeObjectForKey:@"quota"] retain]; + userId = [[coder decodeObjectForKey:@"userId"] retain]; + referralLink = [[coder decodeObjectForKey:@"referralLink"] retain]; + return self; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBCreateAccountController.h b/Classes/ThirdParty/DropboxSDK/DBCreateAccountController.h new file mode 100644 index 0000000..96ad7d7 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBCreateAccountController.h @@ -0,0 +1,36 @@ +// +// DBCreateAccountController.h +// DropboxSDK +// +// Created by Brian Smith on 5/20/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + + +@class DBLoadingView; +@class DBLoginController; +@class DBRestClient; + +@interface DBCreateAccountController : UIViewController { + BOOL hasCreatedAccount; + DBLoginController* loginController; + DBRestClient* restClient; + + UITableView* tableView; + UIView* headerView; + UITableViewCell* firstNameCell; + UITextField* firstNameField; + UITableViewCell* lastNameCell; + UITextField* lastNameField; + UITableViewCell* emailCell; + UITextField* emailField; + UITableViewCell* passwordCell; + UITextField* passwordField; + UIView* footerView; + UIActivityIndicatorView* activityIndicator; + DBLoadingView* loadingView; +} + +@property (nonatomic, assign) DBLoginController* loginController; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBCreateAccountController.m b/Classes/ThirdParty/DropboxSDK/DBCreateAccountController.m new file mode 100644 index 0000000..9447ede --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBCreateAccountController.m @@ -0,0 +1,437 @@ +// +// DBCreateAccountController.m +// DropboxSDK +// +// Created by Brian Smith on 5/20/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBCreateAccountController.h" +#import "DBLoadingView.h" +#import "DBLoginController.h" +#import "DBRestClient.h" + + +enum { + kRowFirstName, + kRowLastName, + kRowEmail, + kRowPassword, + kRowCount +}; + +#define kTextFieldFrame CGRectMake(108, 11, 182, 24) +#define CLEAR_OBJ(FIELD) [FIELD release]; FIELD = nil; + + +@interface DBCreateAccountController () + +- (void)didPressCreateAccount; +- (void)setWorking:(BOOL)working; +- (void)updateActionButton; +- (void)errorWithTitle:(NSString*)title message:(NSString*)message; + +@property (nonatomic, readonly) DBRestClient* restClient; + +@end + + +@implementation DBCreateAccountController + +- (void)viewDidLoad { + [super viewDidLoad]; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + self.title = @"Create Account"; + UIBarButtonItem* saveItem = + [[[UIBarButtonItem alloc] + initWithTitle:@"Create" style:UIBarButtonItemStyleDone + target:self action:@selector(didPressCreateAccount)] + autorelease]; + self.navigationItem.rightBarButtonItem = saveItem; + + } else { + self.title = @"Create Dropbox Account"; + } + + UIImageView* background = + [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"db_background.png"]]; + background.frame = self.view.bounds; + background.autoresizingMask = + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.view addSubview:background]; + [background release]; + + CGRect tableFrame = self.view.bounds; + tableFrame.size.width = 320; + tableFrame.origin.x = floor(self.view.bounds.size.width/2 - tableFrame.size.width/2); + tableView = + [[UITableView alloc] initWithFrame:tableFrame style:UITableViewStyleGrouped]; + tableView.autoresizingMask = + UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | + UIViewAutoresizingFlexibleRightMargin; + tableView.backgroundColor = [UIColor clearColor]; + if ([tableView respondsToSelector:@selector(setBackgroundView:)]) { + [tableView performSelector:@selector(setBackgroundView:) withObject:nil]; + } + tableView.scrollEnabled = NO; + tableView.dataSource = self; + tableView.delegate = self; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + UIView* tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 64)]; + tableView.tableHeaderView = tableHeaderView; + [tableHeaderView release]; + } + [self.view addSubview:tableView]; +} + +- (void)releaseViews { + CLEAR_OBJ(tableView); + CLEAR_OBJ(footerView); + CLEAR_OBJ(firstNameCell); + CLEAR_OBJ(firstNameField); + CLEAR_OBJ(lastNameCell); + CLEAR_OBJ(lastNameField); + CLEAR_OBJ(emailCell); + CLEAR_OBJ(emailField); + CLEAR_OBJ(passwordCell); + CLEAR_OBJ(passwordField); + CLEAR_OBJ(footerView); + CLEAR_OBJ(activityIndicator); + CLEAR_OBJ(loadingView); +} + +- (void)viewDidUnload { + [super viewDidUnload]; + [self releaseViews]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self updateActionButton]; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + [firstNameField becomeFirstResponder]; +} + + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + return interfaceOrientation == UIInterfaceOrientationPortrait; + } else { + return YES; + } +} + + +- (void)dealloc { + [self releaseViews]; + [restClient release]; + [super dealloc]; +} + + +@synthesize loginController; + + +- (IBAction)didPressCreateAccount { + if ([firstNameField.text length] == 0) { + [self errorWithTitle:@"First Name Required" message:@"Please enter your first name."]; + return; + } else if ([lastNameField.text length] == 0) { + [self errorWithTitle:@"Last Name Required" message:@"Please enter your last name."]; + return; + } else if ([emailField.text length] == 0) { + [self errorWithTitle:@"Email Address Required" message:@"Please enter your email address."]; + return; + } else if ([passwordField.text length] == 0) { + [self errorWithTitle:@"Password Required" message:@"Please enter your desired password"]; + return; + } + + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + [firstNameField resignFirstResponder]; + [lastNameField resignFirstResponder]; + [emailField resignFirstResponder]; + [passwordField resignFirstResponder]; + } + [self setWorking:YES]; + + if (!hasCreatedAccount) { + [self.restClient createAccount:emailField.text password:passwordField.text + firstName:firstNameField.text lastName:lastNameField.text]; + } else { + [self.restClient loginWithEmail:emailField.text password:passwordField.text]; + } +} + + +#pragma mark UITextFieldDelegate + +- (BOOL)textFieldShouldReturn:(UITextField*)textField { + if (textField == firstNameField) { + [lastNameField becomeFirstResponder]; + } else if (textField == lastNameField) { + [emailField becomeFirstResponder]; + } else if (textField == emailField) { + [passwordField becomeFirstResponder]; + } else { + [self didPressCreateAccount]; + } + + return YES; +} + + +- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range +replacementString:(NSString *)string { + // Update the button after the replacement has been made + [self performSelector:@selector(updateActionButton) withObject:nil afterDelay:0]; + return YES; +} + + +#pragma mark UITableViewDataSource methods + +- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { + return kRowCount; +} + +- (UITableViewCell*)newCellWithLabel:(NSString*)label textField:(UITextField*)textField { + + UITableViewCell* cell = + [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + cell.textLabel.text = label; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + textField.frame = kTextFieldFrame; + textField.borderStyle = UITextBorderStyleNone; + textField.delegate = self; + [cell.contentView addSubview:textField]; + + return cell; +} + +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { + switch ([indexPath row]) { + case kRowFirstName: + if (!firstNameCell) { + firstNameField = [UITextField new]; + firstNameField.placeholder = @"John"; + firstNameField.returnKeyType = UIReturnKeyNext; + firstNameField.autocorrectionType = UITextAutocorrectionTypeNo; + firstNameCell = [self newCellWithLabel:@"First Name" textField:firstNameField]; + } + return firstNameCell; + case kRowLastName: + if (!lastNameCell) { + lastNameField = [UITextField new]; + lastNameField.placeholder = @"Appleseed"; + lastNameField.returnKeyType = UIReturnKeyNext; + lastNameField.autocorrectionType = UITextAutocorrectionTypeNo; + lastNameCell = [self newCellWithLabel:@"Last Name" textField:lastNameField]; + } + return lastNameCell; + case kRowEmail: + if (!emailCell) { + emailField = [UITextField new]; + emailField.placeholder = @"example@gmail.com"; + emailField.keyboardType = UIKeyboardTypeEmailAddress; + emailField.autocapitalizationType = UITextAutocapitalizationTypeNone; + emailField.returnKeyType = UIReturnKeyNext; + emailField.autocorrectionType = UITextAutocorrectionTypeNo; + emailCell = [self newCellWithLabel:@"Email" textField:emailField]; + } + return emailCell; + case kRowPassword: + if (!passwordCell) { + passwordField = [UITextField new]; + passwordField.secureTextEntry = YES; + passwordField.returnKeyType = UIReturnKeyDone; + passwordField.placeholder = @"Required"; + passwordCell = [self newCellWithLabel:@"Password" textField:passwordField]; + } + return passwordCell; + default: + return nil; + } +} + + +#pragma mark UITableViewDelegate methods + +- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { + switch ([indexPath row]) { + case kRowFirstName: + [firstNameField becomeFirstResponder]; + return; + case kRowLastName: + [lastNameField becomeFirstResponder]; + return; + case kRowEmail: + [emailField becomeFirstResponder]; + return; + case kRowPassword: + [passwordField becomeFirstResponder]; + return; + } +} + +- (CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) return 0; + + return 53; +} + +- (UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) return nil; + + if (headerView == nil) { + headerView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"db_link_header.png"]]; + headerView.contentMode = UIViewContentModeCenter; + } + return headerView; +} + +- (CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) return 0; + + return 80; +} + +- (UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) return nil; + + if (footerView == nil) { + footerView = [UIView new]; + footerView.backgroundColor = [UIColor clearColor]; + + UIButton* createButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [createButton setImage:[UIImage imageNamed:@"db_create_account_button.png"] + forState:UIControlStateNormal]; + [createButton setImage:[UIImage imageNamed:@"db_create_account_button_down.png"] + forState:UIControlStateHighlighted]; + [createButton addTarget:self action:@selector(didPressCreateAccount) + forControlEvents:UIControlEventTouchUpInside]; + [createButton sizeToFit]; + CGRect buttonFrame = createButton.frame; + buttonFrame.origin.x = 320 - buttonFrame.size.width - 8; + buttonFrame.origin.y = 8; + createButton.frame = buttonFrame; + [footerView addSubview:createButton]; + + activityIndicator = [[UIActivityIndicatorView alloc] + initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + CGRect activityFrame = activityIndicator.frame; + activityFrame.origin.x = 320 - activityFrame.size.width - 21; + activityFrame.origin.y = 17; + activityIndicator.frame = activityFrame; + [footerView addSubview:activityIndicator]; + } + return footerView; +} + + +#pragma mark DBRestClientDelegate methods + +- (void)restClientCreatedAccount:(DBRestClient*)client { + hasCreatedAccount = YES; + [self.restClient loginWithEmail:emailField.text password:passwordField.text]; +} + + +- (void)restClient:(DBRestClient*)client createAccountFailedWithError:(NSError*)error { + [self setWorking:NO]; + + NSString* message = @"An unknown error occured."; + if ([error.domain isEqual:NSURLErrorDomain]) { + message = @"There was an error connecting to Dropbox."; + } else { + NSObject* errorResponse = [[error userInfo] objectForKey:@"error"]; + if ([errorResponse isKindOfClass:[NSString class]]) { + message = (NSString*)errorResponse; + } else if ([errorResponse isKindOfClass:[NSDictionary class]]) { + NSDictionary* errorDict = (NSDictionary*)errorResponse; + message = [errorDict objectForKey:[[errorDict allKeys] objectAtIndex:0]]; + } + } + [self errorWithTitle:@"Create Account Failed" message:message]; +} + + +- (void)restClientDidLogin:(DBRestClient*)client { + [self setWorking:NO]; + [self.navigationController.parentViewController dismissModalViewControllerAnimated:YES]; + [loginController.delegate loginControllerDidLogin:loginController]; +} + + +- (void)restClient:(DBRestClient*)client loginFailedWithError:(NSError*)error { + [self setWorking:NO]; + // Need to make sure they don't change the email or password if create account succeeded + // but login failed + emailField.enabled = NO; + passwordField.enabled = NO; + [self errorWithTitle:@"Login Failed" message:@"Please try again."]; +} + + +#pragma mark private methods + +- (void)setWorking:(BOOL)working { + self.view.userInteractionEnabled = !working; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + if (working) { + loadingView = [[DBLoadingView alloc] initWithTitle:@"Creating Account"]; + [loadingView show]; + } else { + [loadingView dismissAnimated:NO]; + [loadingView release]; + loadingView = nil; + } + [self updateActionButton]; + } else { + if (working) { + [activityIndicator startAnimating]; + } else { + [activityIndicator stopAnimating]; + } + } +} + + +- (void)updateActionButton { + self.navigationItem.rightBarButtonItem.enabled = + [firstNameField.text length] > 0 && + [lastNameField.text length] > 0 && + [emailField.text length] > 0 && + [passwordField.text length] > 0 && + !loadingView; +} + + +- (void)errorWithTitle:(NSString*)title message:(NSString*)message { + [[[[UIAlertView alloc] + initWithTitle:title message:message delegate:nil + cancelButtonTitle:@"OK" otherButtonTitles:nil] + autorelease] + show]; +} + + +- (DBRestClient*)restClient { + if (restClient == nil) { + restClient = [[DBRestClient alloc] initWithSession:[DBSession sharedSession]]; + restClient.delegate = self; + } + return restClient; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBError.h b/Classes/ThirdParty/DropboxSDK/DBError.h new file mode 100644 index 0000000..4f87be3 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBError.h @@ -0,0 +1,19 @@ +// +// DBError.h +// DropboxSDK +// +// Created by Brian Smith on 7/21/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +/* This file contains error codes and the dropbox error domain */ + +extern NSString* DBErrorDomain; + +// Error codes in the dropbox.com domain represent the HTTP status code if less than 1000 +typedef enum { + DBErrorNone = 0, + DBErrorGenericError = 1000, + DBErrorFileNotFound, + DBErrorInsufficientDiskSpace, +} DBErrorCode; diff --git a/Classes/ThirdParty/DropboxSDK/DBError.m b/Classes/ThirdParty/DropboxSDK/DBError.m new file mode 100644 index 0000000..790fc0b --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBError.m @@ -0,0 +1,11 @@ +// +// DBError.m +// DropboxSDK +// +// Created by Brian Smith on 7/21/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBError.h" + +NSString* DBErrorDomain = @"dropbox.com"; diff --git a/Classes/ThirdParty/DropboxSDK/DBLoadingView.h b/Classes/ThirdParty/DropboxSDK/DBLoadingView.h new file mode 100644 index 0000000..242fcfa --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBLoadingView.h @@ -0,0 +1,29 @@ +// +// DBLoadingView.h +// DropboxSDK +// +// Created by Brian Smith on 6/30/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import + + +@interface DBLoadingView : UIView { + UIInterfaceOrientation orientation; + UILabel* titleLabel; + UIActivityIndicatorView* activityIndicator; + UIImageView* imageView; +} + +- (id)initWithTitle:(NSString*)title; + +- (void)setImage:(UIImage*)image; +- (void)setOrientation:(UIInterfaceOrientation)orientation; + +- (void)show; +- (void)dismissAnimated:(BOOL)animated; + +//@property (nonatomic, retain) NSString* title; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBLoadingView.m b/Classes/ThirdParty/DropboxSDK/DBLoadingView.m new file mode 100644 index 0000000..4fa9fa6 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBLoadingView.m @@ -0,0 +1,166 @@ +// +// DBLoadingView.m +// DropboxSDK +// +// Created by Brian Smith on 6/30/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBLoadingView.h" + + +#define kPadding 10 + + +@interface DBLoadingView () + +- (CGRect)beveledBoxFrame; + +@end + + +@implementation DBLoadingView + +- (id)init { + return [self initWithTitle:nil]; +} + +- (id)initWithTitle:(NSString*)theTitle { + CGRect frame = [[UIApplication sharedApplication] keyWindow].frame; + if ((self = [super initWithFrame:frame])) { + self.backgroundColor = [UIColor clearColor]; + self.userInteractionEnabled = NO; + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + activityIndicator = + [[UIActivityIndicatorView alloc] + initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + [self addSubview:activityIndicator]; + + imageView = [[UIImageView alloc] init]; + [self addSubview:imageView]; + + titleLabel = [UILabel new]; + titleLabel.text = theTitle; + titleLabel.textColor = [UIColor whiteColor]; + titleLabel.backgroundColor = [UIColor clearColor]; + titleLabel.textAlignment = UITextAlignmentCenter; + [self addSubview:titleLabel]; + } + return self; +} + +- (void)drawRect:(CGRect)rect { + CGRect contentFrame = [self beveledBoxFrame]; + + CGContextRef context = UIGraphicsGetCurrentContext(); + CGFloat fillColor[] = { 0, 0, 0, 128.0/255 }; + CGContextSetFillColor(context, fillColor); + CGFloat radius = 6; + CGContextMoveToPoint(context, contentFrame.origin.x + radius, contentFrame.origin.y); + CGContextAddArcToPoint(context, + CGRectGetMaxX(contentFrame), contentFrame.origin.y, + CGRectGetMaxX(contentFrame), CGRectGetMaxY(contentFrame), radius); + CGContextAddArcToPoint(context, + CGRectGetMaxX(contentFrame), CGRectGetMaxY(contentFrame), + contentFrame.origin.x, CGRectGetMaxY(contentFrame), radius); + CGContextAddArcToPoint(context, + contentFrame.origin.x, CGRectGetMaxY(contentFrame), + contentFrame.origin.x, contentFrame.origin.y, radius); + CGContextAddArcToPoint(context, + contentFrame.origin.x, contentFrame.origin.y, + CGRectGetMaxX(contentFrame), contentFrame.origin.y, radius); + CGContextClosePath(context); + CGContextFillPath(context); +} + +- (void)layoutSubviews { + CGRect contentFrame = [self beveledBoxFrame]; + + activityIndicator.center = CGPointMake( + floor(contentFrame.origin.x + contentFrame.size.width/2), + floor(contentFrame.origin.y + contentFrame.size.height/2) - kPadding); + + CGFloat titleLeading = titleLabel.font.leading; + CGRect titleFrame = CGRectMake( + contentFrame.origin.x + kPadding, + CGRectGetMaxY(contentFrame) - 2*kPadding - titleLeading, + contentFrame.size.width - 2*kPadding, titleLeading); + titleLabel.frame = titleFrame; + + CGRect imageFrame = imageView.frame; + imageFrame.origin.x = contentFrame.origin.x + floor(contentFrame.size.width/2 - imageFrame.size.width/2); + imageFrame.origin.y = contentFrame.origin.y + floor(contentFrame.size.height/2 - imageFrame.size.height/2); + imageView.frame = imageFrame; +} + +- (void)dealloc { + [activityIndicator release]; + [imageView release]; + [titleLabel release]; + [super dealloc]; +} + +- (void)setImage:(UIImage*)image { + imageView.image = image; + [imageView sizeToFit]; + + [self setNeedsLayout]; +} + +- (void)setOrientation:(UIInterfaceOrientation)newOrientation { + if (newOrientation == orientation) return; + orientation = newOrientation; + + if (orientation == UIInterfaceOrientationPortrait) { + self.transform = CGAffineTransformIdentity; + } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { + self.transform = CGAffineTransformMakeRotation(M_PI); + } else if (orientation == UIInterfaceOrientationLandscapeRight) { + self.transform = CGAffineTransformMakeRotation(M_PI/2); + } else { + self.transform = CGAffineTransformMakeRotation(-M_PI/2); + } +} + +- (void)show { + if (!imageView.image) { + // Only show activity indicator when we don't have an image + [activityIndicator startAnimating]; + } + UIWindow* window = [[UIApplication sharedApplication] keyWindow]; + self.frame = window.frame; + [window addSubview:self]; +} + +- (void)finishDismiss { + [activityIndicator stopAnimating]; + [self removeFromSuperview]; +} + +- (void)dismissAnimated:(BOOL)animated { + if (!animated) { + [self finishDismiss]; + } else { + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:0.8]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(finishDismiss)]; + + self.alpha = 0; + + [UIView commitAnimations]; + } +} + +- (CGRect)beveledBoxFrame { + CGSize contentSize = self.bounds.size; + CGSize boxSize = CGSizeMake(160, 160); + CGFloat yOffset = UIInterfaceOrientationIsPortrait(orientation) ? 18 : 0; + return CGRectMake( + floor(contentSize.width/2 - boxSize.width/2), + floor(contentSize.height/2 - boxSize.height/2) + yOffset, + boxSize.width, boxSize.height); +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBLoginController.h b/Classes/ThirdParty/DropboxSDK/DBLoginController.h new file mode 100644 index 0000000..d445482 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBLoginController.h @@ -0,0 +1,46 @@ +// +// DBLoginController.h +// DropboxSDK +// +// Created by Brian Smith on 5/20/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + + +@class DBLoadingView; +@class DBRestClient; +@protocol DBLoginControllerDelegate; + +@interface DBLoginController : UIViewController { + BOOL hasAppeared; // Used to track whether the view totally onscreen + id delegate; + + UITableView* tableView; + UILabel* descriptionLabel; + UITableViewCell* emailCell; + UITextField* emailField; + UITableViewCell* passwordCell; + UITextField* passwordField; + UIView* footerView; + + DBLoadingView* loadingView; + UIActivityIndicatorView* activityIndicator; + + DBRestClient* restClient; +} + +- (void)presentFromController:(UIViewController*)controller; + +@property (nonatomic, assign) id delegate; + +@end + + +// This controller tells the delegate whether the user sucessfully logged in or not +// The login controller will dismiss itself +@protocol DBLoginControllerDelegate + +- (void)loginControllerDidLogin:(DBLoginController*)controller; +- (void)loginControllerDidCancel:(DBLoginController*)controller; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBLoginController.m b/Classes/ThirdParty/DropboxSDK/DBLoginController.m new file mode 100644 index 0000000..628b250 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBLoginController.m @@ -0,0 +1,443 @@ +// +// DBLoginController.m +// DropboxSDK +// +// Created by Brian Smith on 5/20/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBLoadingView.h" +#import "DBLoginController.h" +#import "DBCreateAccountController.h" +#import "DBRestClient.h" + + +#define kTextFieldFrame CGRectMake(100, 11, 190, 24) + + +@interface DBLoginController () + +- (void)didPressLogin; +- (void)didPressCreateAccount; +- (void)setWorking:(BOOL)working; +- (void)errorWithTitle:(NSString*)title message:(NSString*)message; +- (void)updateActionButton; + +@property (nonatomic, readonly) DBRestClient* restClient; + +@end + + +@implementation DBLoginController + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + return interfaceOrientation == UIInterfaceOrientationPortrait; + } else { + return YES; + } +} + +- (void)viewDidLoad { + [super viewDidLoad]; + UIBarButtonItem* cancelItem = + [[[UIBarButtonItem alloc] + initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self action:@selector(didPressCancel)] + autorelease]; + + self.title = @"Link Account"; + + UIImageView* background = + [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"db_background.png"]]; + background.frame = self.view.bounds; + background.autoresizingMask = + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.view addSubview:background]; + [background release]; + + CGRect tableFrame = self.view.bounds; + tableFrame.size.width = 320; + tableFrame.origin.x = floor(self.view.bounds.size.width/2 - tableFrame.size.width/2); + tableView = + [[UITableView alloc] initWithFrame:tableFrame style:UITableViewStyleGrouped]; + tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | + UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; + tableView.backgroundColor = [UIColor clearColor]; + tableView.scrollEnabled = NO; + tableView.delegate = self; + tableView.dataSource = self; + if ([tableView respondsToSelector:@selector(setBackgroundView:)]) { + [tableView performSelector:@selector(setBackgroundView:) withObject:nil]; + } + + UIView* headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 152)]; + UIImageView* logo = + [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"db_logo.png"]]; + logo.contentMode = UIViewContentModeCenter; + logo.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [logo sizeToFit]; + logo.center = headerView.center; + CGRect logoFrame = logo.frame; + logoFrame.origin.y += 7; + logo.frame = logoFrame; + [headerView addSubview:logo]; + tableView.tableHeaderView = headerView; + [headerView release]; + [logo release]; + + UIButton* createAccountButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [createAccountButton + setImage:[UIImage imageNamed:@"db_create_account.png"] + forState:UIControlStateNormal]; + [createAccountButton + addTarget:self action:@selector(didPressCreateAccount) + forControlEvents:UIControlEventTouchUpInside]; + CGFloat createAccountHeight = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone ? 36 : 44; + createAccountButton.frame = CGRectMake(0, 0, 264, createAccountHeight); + tableView.tableFooterView = createAccountButton; + + [self.view addSubview:tableView]; + + self.navigationItem.leftBarButtonItem = cancelItem; + + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + self.navigationItem.rightBarButtonItem = + [[[UIBarButtonItem alloc] + initWithTitle:@"Link" style:UIBarButtonItemStyleDone + target:self action:@selector(didPressLogin)] + autorelease]; + self.navigationItem.backBarButtonItem = + [[[UIBarButtonItem alloc] + initWithTitle:@"Link" style:UIBarButtonItemStylePlain target:nil action:nil] + autorelease]; + } +} + + +- (void)releaseViews { + [tableView release]; + tableView = nil; + [descriptionLabel release]; + descriptionLabel = nil; + [emailCell release]; + emailCell = nil; + [emailField release]; + emailField = nil; + [passwordCell release]; + passwordCell = nil; + [passwordField release]; + passwordField = nil; + [footerView release]; + footerView = nil; + [activityIndicator release]; + activityIndicator = nil; +} + +- (void)viewDidUnload { + [super viewDidUnload]; + [self releaseViews]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self updateActionButton]; +} + +- (void)dealloc { + [loadingView release]; + [restClient release]; + [self releaseViews]; + [super dealloc]; +} + + +- (void)presentFromController:(UIViewController*)controller { + UINavigationController* navController = + [[[UINavigationController alloc] initWithRootViewController:self] autorelease]; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + navController.modalPresentationStyle = UIModalPresentationFormSheet; + } + [controller presentModalViewController:navController animated:YES]; +} + + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + hasAppeared = NO; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + hasAppeared = YES; + + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && + UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) { + + [emailField becomeFirstResponder]; + } +} + + +@synthesize delegate; + + +- (void)didPressLogin { + if ([emailField.text length] == 0) { + [self errorWithTitle:@"Email Required" message:@"Please enter your email."]; + return; + } else if ([passwordField.text length] == 0) { + [self errorWithTitle:@"Password Required" message:@"Please enter you password."]; + return; + } + + [emailField resignFirstResponder]; + [passwordField resignFirstResponder]; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + [tableView setContentOffset:CGPointZero animated:YES]; + } + [self setWorking:YES]; + + [self.restClient loginWithEmail:emailField.text password:passwordField.text]; +} + + +- (void)didPressCreateAccount { + DBCreateAccountController* createAccountController = + [[DBCreateAccountController new] autorelease]; + createAccountController.loginController = self; + [self.navigationController pushViewController:createAccountController animated:YES]; +} + + +- (void)didPressCancel { + [self setWorking:NO]; + [self.navigationController.parentViewController dismissModalViewControllerAnimated:YES]; + [delegate loginControllerDidCancel:self]; +} + + +#pragma mark UITextFieldDelegate methods + +- (BOOL)textFieldShouldBeginEditing:(UITextField*)textField { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + [tableView setContentOffset:CGPointMake(0, 150) animated:hasAppeared]; + } + return YES; +} + +- (BOOL)textFieldShouldReturn:(UITextField*)textField { + if (textField == emailField) { + [passwordField becomeFirstResponder]; + } else { + [self didPressLogin]; + } + + return YES; +} + +- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range +replacementString:(NSString *)string { + [self performSelector:@selector(updateActionButton) withObject:nil afterDelay:0]; + return YES; +} + + +#pragma mark UITableViewDataSource methods + +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { + return section == 0 ? 2 : 0; +} + +- (UITableViewCell*)newCellWithTitle:(NSString*)title textField:(UITextField*)textField { + UITableViewCell* cell = + [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + cell.textLabel.text = title; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + textField.frame = kTextFieldFrame; + textField.borderStyle = UITextBorderStyleNone; + textField.delegate = self; + [cell.contentView addSubview:textField]; + return cell; +} + +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { + if ([indexPath row] == 0) { + if (!emailCell) { + emailField = [UITextField new]; + emailField.placeholder = @"example@gmail.com"; + emailField.keyboardType = UIKeyboardTypeEmailAddress; + emailField.returnKeyType = UIReturnKeyNext; + emailField.autocapitalizationType = UITextAutocapitalizationTypeNone; + emailField.autocorrectionType = UITextAutocorrectionTypeNo; + emailCell = [self newCellWithTitle:@"Email" textField:emailField]; + } + return emailCell; + } else { + if (!passwordCell) { + passwordField = [UITextField new]; + passwordField.placeholder = @"Required"; + passwordField.secureTextEntry = YES; + passwordField.returnKeyType = UIReturnKeyDone; + passwordCell = [self newCellWithTitle:@"Password" textField:passwordField]; + } + return passwordCell; + } +} + + +#pragma mark UITableViewDelegate methods + +- (CGFloat)tableView:(UITableView*)tableView heightForHeaderInSection:(NSInteger)section { + if (section != 0) return 0; + + return 53; +} + +- (UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section { + if (section != 0) return nil; + + if (!descriptionLabel) { + descriptionLabel = + [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"db_link_header.png"]]; + descriptionLabel.contentMode = UIViewContentModeCenter; +/* + descriptionLabel = [UILabel new]; + descriptionLabel.backgroundColor = [UIColor clearColor]; + descriptionLabel.textColor = [UIColor whiteColor]; + descriptionLabel.font = [UIFont systemFontOfSize:15]; + descriptionLabel.textAlignment = UITextAlignmentCenter; + descriptionLabel.text = + @"Linking will allow this app to access\nand modify files in your Dropbox"; + descriptionLabel.numberOfLines = 2; +*/ + } + return descriptionLabel; +} + +- (CGFloat)tableView:(UITableView*)tableView heightForFooterInSection:(NSInteger)section { + return UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? 80 : 0; +} + +- (UIView*)tableView:(UITableView*)tableView viewForFooterInSection:(NSInteger)section { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) return nil; + + if (footerView == nil) { + footerView = [[UIView alloc] init]; + footerView.backgroundColor = [UIColor clearColor]; + UIButton* linkButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [linkButton addTarget:self action:@selector(didPressLogin) + forControlEvents:UIControlEventTouchUpInside]; + [linkButton setImage:[UIImage imageNamed:@"db_link_button.png"] + forState:UIControlStateNormal]; + [linkButton setImage:[UIImage imageNamed:@"db_link_button_down.png"] + forState:UIControlStateHighlighted]; + [linkButton sizeToFit]; + CGRect linkFrame = linkButton.frame; + linkFrame.origin.x = 320 - linkFrame.size.width - 8; + linkFrame.origin.y = 8; + linkButton.frame = linkFrame; + [footerView addSubview:linkButton]; + + activityIndicator = [[UIActivityIndicatorView alloc] + initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; + CGRect activityFrame = activityIndicator.frame; + activityFrame.origin.x = 320 - activityFrame.size.width - 21; + activityFrame.origin.y = 17; + activityIndicator.frame = activityFrame; + [footerView addSubview:activityIndicator]; + } + return footerView; +} + +- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { + if ([indexPath row] == 0) { + [emailField becomeFirstResponder]; + } else { + [passwordField becomeFirstResponder]; + } +} + + +#pragma mark DBRestClient methods + +- (void)restClientDidLogin:(DBRestClient*)client { + [self setWorking:NO]; + [self.parentViewController dismissModalViewControllerAnimated:YES]; + [delegate loginControllerDidLogin:self]; +} + + +- (void)restClient:(DBRestClient*)client loginFailedWithError:(NSError*)error { + [self setWorking:NO]; + + NSString* message; + if ([error.domain isEqual:NSURLErrorDomain]) { + message = @"There was an error connecting to Dropbox."; + } else { + NSObject* errorResponse = [[error userInfo] objectForKey:@"error"]; + if ([errorResponse isKindOfClass:[NSString class]]) { + message = (NSString*)errorResponse; + } else if ([errorResponse isKindOfClass:[NSDictionary class]]) { + NSDictionary* errorDict = (NSDictionary*)errorResponse; + message = [errorDict objectForKey:[[errorDict allKeys] objectAtIndex:0]]; + } else { + message = @"An unknown error has occurred."; + } + } + [self errorWithTitle:@"Unable to Login" message:message]; +} + + +#pragma mark private methods + +- (void)setWorking:(BOOL)working { + self.view.userInteractionEnabled = !working; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + if (working) { + loadingView = [[DBLoadingView alloc] initWithTitle:@"Linking"]; + [loadingView show]; + } else { + [loadingView dismissAnimated:NO]; + [loadingView release]; + loadingView = nil; + } + [self updateActionButton]; + } else { + if (working) { + [activityIndicator startAnimating]; + } else { + [activityIndicator stopAnimating]; + } + } +} + + +- (void)errorWithTitle:(NSString*)title message:(NSString*)message { + [[[[UIAlertView alloc] + initWithTitle:title message:message delegate:nil + cancelButtonTitle:@"OK" otherButtonTitles:nil] + autorelease] + show]; +} + + +- (void)updateActionButton { + self.navigationItem.rightBarButtonItem.enabled = + [emailField.text length] > 0 && + [passwordField.text length] > 0 && + !loadingView; +} + + +- (DBRestClient*)restClient { + if (restClient == nil) { + restClient = [[DBRestClient alloc] initWithSession:[DBSession sharedSession]]; + restClient.delegate = self; + } + return restClient; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBMetadata.h b/Classes/ThirdParty/DropboxSDK/DBMetadata.h new file mode 100644 index 0000000..032fc46 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBMetadata.h @@ -0,0 +1,40 @@ +// +// DBMetadata.h +// DropboxSDK +// +// Created by Brian Smith on 5/3/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + + +@interface DBMetadata : NSObject { + BOOL thumbnailExists; + long long totalBytes; + NSDate* lastModifiedDate; + NSString* path; + BOOL isDirectory; + NSArray* contents; + NSString* hash; + NSString* humanReadableSize; + NSString* root; + NSString* icon; + long long revision; + BOOL isDeleted; +} + +- (id)initWithDictionary:(NSDictionary*)dict; + +@property (nonatomic, readonly) BOOL thumbnailExists; +@property (nonatomic, readonly) long long totalBytes; +@property (nonatomic, readonly) NSDate* lastModifiedDate; +@property (nonatomic, readonly) NSString* path; +@property (nonatomic, readonly) BOOL isDirectory; +@property (nonatomic, readonly) NSArray* contents; +@property (nonatomic, readonly) NSString* hash; +@property (nonatomic, readonly) NSString* humanReadableSize; +@property (nonatomic, readonly) NSString* root; +@property (nonatomic, readonly) NSString* icon; +@property (nonatomic, readonly) long long revision; +@property (nonatomic, readonly) BOOL isDeleted; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBMetadata.m b/Classes/ThirdParty/DropboxSDK/DBMetadata.m new file mode 100644 index 0000000..195c61d --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBMetadata.m @@ -0,0 +1,126 @@ +// +// DBMetadata.m +// DropboxSDK +// +// Created by Brian Smith on 5/3/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBMetadata.h" + +@implementation DBMetadata + ++ (NSDateFormatter*)dateFormatter { + NSMutableDictionary* dictionary = [[NSThread currentThread] threadDictionary]; + static NSString* dateFormatterKey = @"DBMetadataDateFormatter"; + + NSDateFormatter* dateFormatter = [dictionary objectForKey:dateFormatterKey]; + if (dateFormatter == nil) { + dateFormatter = [[NSDateFormatter new] autorelease]; + // Must set locale to ensure consistent parsing: + // http://developer.apple.com/iphone/library/qa/qa2010/qa1480.html + dateFormatter.locale = + [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; + dateFormatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss Z"; + [dictionary setObject:dateFormatter forKey:dateFormatterKey]; + } + return dateFormatter; +} + +- (id)initWithDictionary:(NSDictionary*)dict { + if ((self = [super init])) { + thumbnailExists = [[dict objectForKey:@"thumb_exists"] boolValue]; + totalBytes = [[dict objectForKey:@"bytes"] longLongValue]; + + if ([dict objectForKey:@"modified"]) { + lastModifiedDate = + [[[DBMetadata dateFormatter] dateFromString:[dict objectForKey:@"modified"]] retain]; + } + + path = [[dict objectForKey:@"path"] retain]; + isDirectory = [[dict objectForKey:@"is_dir"] boolValue]; + + if ([dict objectForKey:@"contents"]) { + NSArray* subfileDicts = [dict objectForKey:@"contents"]; + NSMutableArray* mutableContents = + [[NSMutableArray alloc] initWithCapacity:[subfileDicts count]]; + for (NSDictionary* subfileDict in subfileDicts) { + DBMetadata* subfile = [[DBMetadata alloc] initWithDictionary:subfileDict]; + [mutableContents addObject:subfile]; + [subfile release]; + } + contents = mutableContents; + } + + hash = [[dict objectForKey:@"hash"] retain]; + humanReadableSize = [[dict objectForKey:@"size"] retain]; + root = [[dict objectForKey:@"root"] retain]; + icon = [[dict objectForKey:@"icon"] retain]; + revision = [[dict objectForKey:@"revision"] longLongValue]; + isDeleted = [[dict objectForKey:@"is_deleted"] boolValue]; + } + return self; +} + +- (void)dealloc { + [lastModifiedDate release]; + [path release]; + [contents release]; + [hash release]; + [humanReadableSize release]; + [root release]; + [icon release]; + [super dealloc]; +} + +@synthesize thumbnailExists; +@synthesize totalBytes; +@synthesize lastModifiedDate; +@synthesize path; +@synthesize isDirectory; +@synthesize contents; +@synthesize hash; +@synthesize humanReadableSize; +@synthesize root; +@synthesize icon; +@synthesize revision; +@synthesize isDeleted; + + +#pragma mark NSCoding methods + +- (id)initWithCoder:(NSCoder*)coder { + if ((self = [super init])) { + thumbnailExists = [coder decodeBoolForKey:@"thumbnailExists"]; + totalBytes = [coder decodeInt64ForKey:@"totalBytes"]; + lastModifiedDate = [[coder decodeObjectForKey:@"lastModifiedDate"] retain]; + path = [[coder decodeObjectForKey:@"path"] retain]; + isDirectory = [coder decodeBoolForKey:@"isDirectory"]; + contents = [[coder decodeObjectForKey:@"contents"] retain]; + hash = [[coder decodeObjectForKey:@"hash"] retain]; + humanReadableSize = [[coder decodeObjectForKey:@"humanReadableSize"] retain]; + root = [[coder decodeObjectForKey:@"root"] retain]; + icon = [[coder decodeObjectForKey:@"icon"] retain]; + revision = [coder decodeInt64ForKey:@"revision"]; + isDeleted = [coder decodeBoolForKey:@"isDeleted"]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder*)coder { + [coder encodeBool:thumbnailExists forKey:@"thumbnailExists"]; + [coder encodeInt64:totalBytes forKey:@"totalBytes"]; + [coder encodeObject:lastModifiedDate forKey:@"lastModifiedDate"]; + [coder encodeObject:path forKey:@"path"]; + [coder encodeBool:isDirectory forKey:@"isDirectory"]; + [coder encodeObject:contents forKey:@"contents"]; + [coder encodeObject:hash forKey:@"hash"]; + [coder encodeObject:humanReadableSize forKey:@"humanReadableSize"]; + [coder encodeObject:root forKey:@"root"]; + [coder encodeObject:icon forKey:@"icon"]; + [coder encodeInt64:revision forKey:@"revision"]; + [coder encodeBool:isDeleted forKey:@"isDeleted"]; +} + + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBQuota.h b/Classes/ThirdParty/DropboxSDK/DBQuota.h new file mode 100644 index 0000000..b5cef72 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBQuota.h @@ -0,0 +1,23 @@ +// +// DBQuota.h +// DropboxSDK +// +// Created by Brian Smith on 5/3/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + + +@interface DBQuota : NSObject { + long long normalConsumedBytes; + long long sharedConsumedBytes; + long long totalBytes; +} + +- (id)initWithDictionary:(NSDictionary*)dict; + +@property (nonatomic, readonly) long long normalConsumedBytes; +@property (nonatomic, readonly) long long sharedConsumedBytes; +@property (nonatomic, readonly) long long totalConsumedBytes; +@property (nonatomic, readonly) long long totalBytes; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBQuota.m b/Classes/ThirdParty/DropboxSDK/DBQuota.m new file mode 100644 index 0000000..71ab624 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBQuota.m @@ -0,0 +1,52 @@ +// +// DBQuotaInfo.m +// DropboxSDK +// +// Created by Brian Smith on 5/3/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBQuota.h" + + +@implementation DBQuota + +- (id)initWithDictionary:(NSDictionary*)dict { + if ((self = [super init])) { + normalConsumedBytes = [[dict objectForKey:@"normal"] longLongValue]; + sharedConsumedBytes = [[dict objectForKey:@"shared"] longLongValue]; + totalBytes = [[dict objectForKey:@"quota"] longLongValue]; + } + return self; +} + +- (void)dealloc { + [super dealloc]; +} + +@synthesize normalConsumedBytes; +@synthesize sharedConsumedBytes; +@synthesize totalBytes; + +- (long long)totalConsumedBytes { + return normalConsumedBytes + sharedConsumedBytes; +} + + +#pragma mark NSCoding methods + +- (void)encodeWithCoder:(NSCoder*)coder { + [coder encodeInt64:normalConsumedBytes forKey:@"normalConsumedBytes"]; + [coder encodeInt64:sharedConsumedBytes forKey:@"sharedConsumedBytes"]; + [coder encodeInt64:totalBytes forKey:@"totalBytes"]; +} + +- (id)initWithCoder:(NSCoder*)coder { + self = [super init]; + normalConsumedBytes = [coder decodeInt64ForKey:@"normalConsumedBytes"]; + sharedConsumedBytes = [coder decodeInt64ForKey:@"sharedConsumedBytes"]; + totalBytes = [coder decodeInt64ForKey:@"totalBytes"]; + return self; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBRequest.h b/Classes/ThirdParty/DropboxSDK/DBRequest.h new file mode 100644 index 0000000..f051874 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBRequest.h @@ -0,0 +1,71 @@ +// +// DBRestRequest.h +// DropboxSDK +// +// Created by Brian Smith on 4/9/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + + +@protocol DBNetworkRequestDelegate; + +/* DBRestRequest will download a URL either into a file that you provied the name to or it will + create an NSData object with the result. When it has completed downloading the URL, it will + notify the target with a selector that takes the DBRestRequest as the only parameter. */ +@interface DBRequest : NSObject { + NSURLRequest* request; + id target; + SEL selector; + NSURLConnection* urlConnection; + NSFileHandle* fileHandle; + + SEL failureSelector; + SEL downloadProgressSelector; + SEL uploadProgressSelector; + NSString* resultFilename; + NSString* tempFilename; + NSDictionary* userInfo; + + NSHTTPURLResponse* response; + NSInteger bytesDownloaded; + CGFloat downloadProgress; + CGFloat uploadProgress; + NSMutableData* resultData; + NSError* error; +} + +/* Set this to get called when _any_ request starts or stops. This should hook into whatever + network activity indicator system you have. */ ++ (void)setNetworkRequestDelegate:(id)delegate; + +/* This constructor downloads the URL into the resultData object */ +- (id)initWithURLRequest:(NSURLRequest*)request andInformTarget:(id)target selector:(SEL)selector; + +/* Cancels the request and prevents it from sending additional messages to the delegate. */ +- (void)cancel; + +@property (nonatomic, assign) SEL failureSelector; // To send failure events to a different selector set this +@property (nonatomic, assign) SEL downloadProgressSelector; // To receive download progress events set this +@property (nonatomic, assign) SEL uploadProgressSelector; // To receive upload progress events set this +@property (nonatomic, retain) NSString* resultFilename; // The file to put the HTTP body in, otherwise body is stored in resultData +@property (nonatomic, retain) NSDictionary* userInfo; + +@property (nonatomic, readonly) NSURLRequest* request; +@property (nonatomic, readonly) NSHTTPURLResponse* response; +@property (nonatomic, readonly) NSInteger statusCode; +@property (nonatomic, readonly) CGFloat downloadProgress; +@property (nonatomic, readonly) CGFloat uploadProgress; +@property (nonatomic, readonly) NSData* resultData; +@property (nonatomic, readonly) NSString* resultString; +@property (nonatomic, readonly) NSObject* resultJSON; +@property (nonatomic, readonly) NSError* error; + +@end + + +@protocol DBNetworkRequestDelegate + +- (void)networkRequestStarted; +- (void)networkRequestStopped; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBRequest.m b/Classes/ThirdParty/DropboxSDK/DBRequest.m new file mode 100644 index 0000000..491d9c3 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBRequest.m @@ -0,0 +1,228 @@ +// +// DBRestRequest.m +// DropboxSDK +// +// Created by Brian Smith on 4/9/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBRequest.h" +#import "DBError.h" +#import "JSON.h" + + +static id networkRequestDelegate = nil; + +@implementation DBRequest + ++ (void)setNetworkRequestDelegate:(id)delegate { + networkRequestDelegate = delegate; +} + +- (id)initWithURLRequest:(NSURLRequest*)aRequest andInformTarget:(id)aTarget selector:(SEL)aSelector { + if ((self = [super init])) { + request = [aRequest retain]; + target = aTarget; + selector = aSelector; + + urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; + [networkRequestDelegate networkRequestStarted]; + } + return self; +} + +- (void) dealloc { + [urlConnection cancel]; + + [request release]; + [urlConnection release]; + [fileHandle release]; + [userInfo release]; + [response release]; + [resultFilename release]; + [tempFilename release]; + [resultData release]; + [error release]; + [super dealloc]; +} + +@synthesize failureSelector; +@synthesize downloadProgressSelector; +@synthesize uploadProgressSelector; +@synthesize userInfo; +@synthesize request; +@synthesize response; +@synthesize downloadProgress; +@synthesize uploadProgress; +@synthesize resultData; +@synthesize resultFilename; +@synthesize error; + +- (NSString*)resultString { + return [[[NSString alloc] + initWithData:resultData encoding:NSUTF8StringEncoding] + autorelease]; +} + +- (NSObject*)resultJSON { + return [[self resultString] JSONValue]; +} + +- (NSInteger)statusCode { + return [response statusCode]; +} + +- (void)cancel { + [urlConnection cancel]; + target = nil; + + if (tempFilename) { + [fileHandle closeFile]; + NSError* rmError; + if (![[NSFileManager defaultManager] removeItemAtPath:tempFilename error:&rmError]) { + NSLog(@"DBRequest#cancel Error removing temp file: %@", rmError); + } + } + + [networkRequestDelegate networkRequestStopped]; +} + +#pragma mark NSURLConnection delegate methods + +- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)aResponse { + response = [(NSHTTPURLResponse*)aResponse retain]; + + if (resultFilename && [self statusCode] == 200) { + // Create the file here so it's created in case it's zero length + // File is downloaded into a temporary file and then moved over when completed successfully + NSString* filename = + [NSString stringWithFormat:@"%.0f", 1000*[NSDate timeIntervalSinceReferenceDate]]; + tempFilename = [[NSTemporaryDirectory() stringByAppendingPathComponent:filename] retain]; + + NSFileManager* fileManager = [[NSFileManager new] autorelease]; + BOOL success = [fileManager createFileAtPath:tempFilename contents:nil attributes:nil]; + if (!success) { + NSLog(@"DBRequest#connection:didReceiveData: Error creating file at path: %@", + tempFilename); + } + + fileHandle = [[NSFileHandle fileHandleForWritingAtPath:tempFilename] retain]; + } +} + +- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { + if (resultFilename && [self statusCode] == 200) { + @try { + [fileHandle writeData:data]; + } @catch (NSException* e) { + // In case we run out of disk space + [urlConnection cancel]; + [fileHandle closeFile]; + [[NSFileManager defaultManager] removeItemAtPath:tempFilename error:nil]; + error = [[NSError alloc] initWithDomain:DBErrorDomain + code:DBErrorInsufficientDiskSpace userInfo:userInfo]; + + SEL sel = failureSelector ? failureSelector : selector; + [target performSelector:sel withObject:self]; + + [networkRequestDelegate networkRequestStopped]; + + return; + } + } else { + if (resultData == nil) { + resultData = [NSMutableData new]; + } + [resultData appendData:data]; + } + + bytesDownloaded += [data length]; + NSInteger contentLength = [[[response allHeaderFields] objectForKey:@"Content-Length"] intValue]; + downloadProgress = (CGFloat)bytesDownloaded / (CGFloat)contentLength; + if (downloadProgressSelector) { + [target performSelector:downloadProgressSelector withObject:self]; + } +} + +- (void)connectionDidFinishLoading:(NSURLConnection*)connection { + [fileHandle closeFile]; + [fileHandle release]; + fileHandle = nil; + + if (self.statusCode != 200) { + NSMutableDictionary* errorUserInfo = [NSMutableDictionary dictionaryWithDictionary:userInfo]; + // To get error userInfo, first try and make sense of the response as JSON, if that + // fails then send back the string as an error message + NSString* resultString = [self resultString]; + if ([resultString length] > 0) { + @try { + SBJsonParser *jsonParser = [SBJsonParser new]; + NSObject* resultJSON = [jsonParser objectWithString:resultString]; + [jsonParser release]; + + if ([resultJSON isKindOfClass:[NSDictionary class]]) { + [errorUserInfo addEntriesFromDictionary:(NSDictionary*)resultJSON]; + } + } @catch (NSException* e) { + [errorUserInfo setObject:resultString forKey:@"errorMessage"]; + } + } + error = [[NSError alloc] initWithDomain:@"dropbox.com" code:self.statusCode userInfo:errorUserInfo]; + } else if (tempFilename) { + // Move temp file over to desired file + NSFileManager* fileManager = [[NSFileManager new] autorelease]; + [fileManager removeItemAtPath:resultFilename error:nil]; + NSError* moveError; + BOOL success = [fileManager moveItemAtPath:tempFilename toPath:resultFilename error:&moveError]; + if (!success) { + NSLog(@"DBRequest#connectionDidFinishLoading: error moving temp file to desired location: %@", + [moveError localizedDescription]); + error = [[NSError alloc] initWithDomain:moveError.domain code:moveError.code userInfo:self.userInfo]; + } + + [tempFilename release]; + tempFilename = nil; + } + + SEL sel = (error && failureSelector) ? failureSelector : selector; + [target performSelector:sel withObject:self]; + + [networkRequestDelegate networkRequestStopped]; +} + +- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)anError { + [fileHandle closeFile]; + error = [[NSError alloc] initWithDomain:anError.domain code:anError.code userInfo:self.userInfo]; + bytesDownloaded = 0; + downloadProgress = 0; + uploadProgress = 0; + + if (tempFilename) { + NSFileManager* fileManager = [[NSFileManager new] autorelease]; + NSError* removeError; + BOOL success = [fileManager removeItemAtPath:tempFilename error:&removeError]; + if (!success) { + NSLog(@"DBRequest#connection:didFailWithError: error removing temporary file: %@", + [removeError localizedDescription]); + } + [tempFilename release]; + tempFilename = nil; + } + + SEL sel = failureSelector ? failureSelector : selector; + [target performSelector:sel withObject:self]; + + [networkRequestDelegate networkRequestStopped]; +} + +- (void)connection:(NSURLConnection*)connection didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten + totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { + + uploadProgress = (CGFloat)totalBytesWritten / (CGFloat)totalBytesExpectedToWrite; + if (uploadProgressSelector) { + [target performSelector:uploadProgressSelector withObject:self]; + } +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBRestClient.h b/Classes/ThirdParty/DropboxSDK/DBRestClient.h new file mode 100644 index 0000000..465189f --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBRestClient.h @@ -0,0 +1,138 @@ +// +// DBRestClient.h +// DropboxSDK +// +// Created by Brian Smith on 4/9/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + + +#import "DBSession.h" + +@protocol DBRestClientDelegate; +@class DBAccountInfo; +@class DBMetadata; + +extern NSString* kDBProtocolHTTP; +extern NSString* kDBProtocolHTTPS; + +@interface DBRestClient : NSObject { + DBSession* session; + NSString* root; + NSMutableSet* requests; + /* Map from path to the load request. Needs to be expanded to a general framework for cancelling + requests. */ + NSMutableDictionary* loadRequests; + id delegate; +} + +- (id)initWithSession:(DBSession*)session; + +/* New developers should not use this method, and instead just use initWithSession: */ +- (id)initWithSession:(DBSession *)session root:(NSString*)root; + +/* Logs in as the user with the given email/password and stores the OAuth tokens on the session + object */ +- (void)loginWithEmail:(NSString*)email password:(NSString*)password; + +/* Loads metadata for the object at the given root/path and returns the result to the delegate as a + dictionary */ +- (void)loadMetadata:(NSString*)path withHash:(NSString*)hash; +- (void)loadMetadata:(NSString*)path; + +/* Loads the file contents at the given root/path and stores the result into destinationPath */ +- (void)loadFile:(NSString *)path intoPath:(NSString *)destinationPath; +- (void)cancelFileLoad:(NSString*)path; + +- (void)loadThumbnail:(NSString *)path ofSize:(NSString *)size intoPath:(NSString *)destinationPath; + +/* Uploads a file that will be named filename to the given root/path on the server. It will upload + the contents of the file at sourcePath */ +- (void)uploadFile:(NSString*)filename toPath:(NSString*)path fromPath:(NSString *)sourcePath; + +/* Creates a folder at the given root/path */ +- (void)createFolder:(NSString*)path; + +- (void)deletePath:(NSString*)path; + +- (void)copyFrom:(NSString*)from_path toPath:(NSString *)to_path; + +- (void)moveFrom:(NSString*)from_path toPath:(NSString *)to_path; + +- (void)loadAccountInfo; + +- (void)createAccount:(NSString *)email password:(NSString *)password firstName:(NSString *)firstName + lastName:(NSString *)lastName; + +@property (nonatomic, assign) id delegate; + +@end + + + + +/* The delegate provides allows the user to get the result of the calls made on the DBRestClient. + Right now, the error parameter of failed calls may be nil and [error localizedDescription] does + not contain an error message appropriate to show to the user. */ +@protocol DBRestClientDelegate + +@optional + +- (void)restClientDidLogin:(DBRestClient*)client; +- (void)restClient:(DBRestClient*)client loginFailedWithError:(NSError*)error; + +- (void)restClient:(DBRestClient*)client loadedMetadata:(DBMetadata*)metadata; +- (void)restClient:(DBRestClient*)client metadataUnchangedAtPath:(NSString*)path; +- (void)restClient:(DBRestClient*)client loadMetadataFailedWithError:(NSError*)error; +// [error userInfo] contains the root and path of the call that failed + +- (void)restClient:(DBRestClient*)client loadedAccountInfo:(DBAccountInfo*)info; +- (void)restClient:(DBRestClient*)client loadAccountInfoFailedWithError:(NSError*)error; + +- (void)restClient:(DBRestClient*)client loadedFile:(NSString*)destPath; +// Implement the following callback instead of the previous if you care about the value of the +// Content-Type HTTP header. Only one will be called per successful response. +- (void)restClient:(DBRestClient*)client loadedFile:(NSString*)destPath contentType:(NSString*)contentType; +- (void)restClient:(DBRestClient*)client loadProgress:(CGFloat)progress forFile:(NSString*)destPath; +- (void)restClient:(DBRestClient*)client loadFileFailedWithError:(NSError*)error; +// [error userInfo] contains the destinationPath + +- (void)restClient:(DBRestClient*)client loadedThumbnail:(NSString*)destPath; +- (void)restClient:(DBRestClient*)client loadThumbnailFailedWithError:(NSError*)error; + +- (void)restClient:(DBRestClient*)client uploadedFile:(NSString*)destPath from:(NSString*)srcPath; +- (void)restClient:(DBRestClient*)client uploadProgress:(CGFloat)progress +forFile:(NSString*)destPath from:(NSString*)srcPath; +- (void)restClient:(DBRestClient*)client uploadFileFailedWithError:(NSError*)error; +// [error userInfo] contains the sourcePath + +// Deprecated upload callbacks +- (void)restClient:(DBRestClient*)client uploadedFile:(NSString*)srcPath; +- (void)restClient:(DBRestClient*)client uploadProgress:(CGFloat)progress forFile:(NSString*)srcPath; + +- (void)restClient:(DBRestClient*)client createdFolder:(DBMetadata*)folder; +// Folder is the metadata for the newly created folder +- (void)restClient:(DBRestClient*)client createFolderFailedWithError:(NSError*)error; +// [error userInfo] contains the root and path + +- (void)restClient:(DBRestClient*)client deletedPath:(NSString *)path; +// Folder is the metadata for the newly created folder +- (void)restClient:(DBRestClient*)client deletePathFailedWithError:(NSError*)error; +// [error userInfo] contains the root and path + +- (void)restClient:(DBRestClient*)client copiedPath:(NSString *)from_path toPath:(NSString *)to_path; +// Folder is the metadata for the newly created folder +- (void)restClient:(DBRestClient*)client copyPathFailedWithError:(NSError*)error; +// [error userInfo] contains the root and path +// +- (void)restClient:(DBRestClient*)client movedPath:(NSString *)from_path toPath:(NSString *)to_path; +// Folder is the metadata for the newly created folder +- (void)restClient:(DBRestClient*)client movePathFailedWithError:(NSError*)error; +// [error userInfo] contains the root and path + +- (void)restClientCreatedAccount:(DBRestClient*)client; +- (void)restClient:(DBRestClient*)client createAccountFailedWithError:(NSError *)error; + +@end + + diff --git a/Classes/ThirdParty/DropboxSDK/DBRestClient.m b/Classes/ThirdParty/DropboxSDK/DBRestClient.m new file mode 100644 index 0000000..6535beb --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBRestClient.m @@ -0,0 +1,800 @@ +// +// DBRestClient.m +// DropboxSDK +// +// Created by Brian Smith on 4/9/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBRestClient.h" +#import "DBAccountInfo.h" +#import "DBError.h" +#import "DBMetadata.h" +#import "DBRequest.h" +#import "MPOAuthURLRequest.h" +#import "MPURLRequestParameter.h" +#import "MPOAuthSignatureParameter.h" +#import "NSString+URLEscapingAdditions.h" + + +NSString* kDBProtocolHTTP = @"http"; +NSString* kDBProtocolHTTPS = @"https"; + + +@interface DBRestClient () + +// This method escapes all URI escape characters except / ++ (NSString*)escapePath:(NSString*)path; + +- (NSMutableURLRequest*)requestWithProtocol:(NSString*)protocol host:(NSString*)host path:(NSString*)path + parameters:(NSDictionary*)params; + +- (NSMutableURLRequest*)requestWithProtocol:(NSString*)protocol host:(NSString*)host path:(NSString*)path + parameters:(NSDictionary*)params method:(NSString*)method; + +- (void)checkForAuthenticationFailure:(DBRequest*)request; + +@end + + +@implementation DBRestClient + +- (id)initWithSession:(DBSession*)aSession { + return [self initWithSession:aSession root:@"dropbox"]; +} + +- (id)initWithSession:(DBSession*)aSession root:(NSString*)aRoot { + if ((self = [super init])) { + session = [aSession retain]; + root = [aRoot retain]; + requests = [[NSMutableSet alloc] init]; + loadRequests = [[NSMutableDictionary alloc] init]; + } + return self; +} + + +- (void)dealloc { + for (DBRequest* request in requests) { + [request cancel]; + } + [requests release]; + for (DBRequest* request in [loadRequests allValues]) { + [request cancel]; + } + [loadRequests release]; + [session release]; + [root release]; + [super dealloc]; +} + + + +@synthesize delegate; + + +- (void)loginWithEmail:(NSString*)email password:(NSString*)password { + NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: + email, @"email", + password, @"password", nil]; + + NSURLRequest* urlRequest = [self requestWithProtocol:kDBProtocolHTTPS host:kDBDropboxAPIHost + path:@"/token" parameters:params]; + + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidLogin:)] + autorelease]; + + [requests addObject:request]; +} + + + +- (void)requestDidLogin:(DBRequest*)request { + if (request.error) { + if ([delegate respondsToSelector:@selector(restClient:loginFailedWithError:)]) { + [delegate restClient:self loginFailedWithError:request.error]; + } + } else { + NSDictionary* result = (NSDictionary*)request.resultJSON; + NSString* token = [result objectForKey:@"token"]; + NSString* secret = [result objectForKey:@"secret"]; + [session updateAccessToken:token accessTokenSecret:secret]; + if ([delegate respondsToSelector:@selector(restClientDidLogin:)]) { + [delegate restClientDidLogin:self]; + } + } + + [requests removeObject:request]; +} + + + +- (void)loadMetadata:(NSString*)path withHash:(NSString*)hash +{ + NSDictionary* params = nil; + if (hash) { + params = [NSDictionary dictionaryWithObject:hash forKey:@"hash"]; + } + + NSString* fullPath = [NSString stringWithFormat:@"/metadata/%@%@", root, path]; + NSURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTP host:kDBDropboxAPIHost path:fullPath parameters:params]; + + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidLoadMetadata:)] + autorelease]; + + request.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:root, @"root", path, @"path", nil]; + + [requests addObject:request]; +} + +- (void)loadMetadata:(NSString*)path +{ + [self loadMetadata:path withHash:nil]; +} + + +- (void)requestDidLoadMetadata:(DBRequest*)request +{ + if (request.statusCode == 304) { + if ([delegate respondsToSelector:@selector(restClient:metadataUnchangedAtPath:)]) { + NSString* path = [request.userInfo objectForKey:@"path"]; + [delegate restClient:self metadataUnchangedAtPath:path]; + } + } else if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:loadMetadataFailedWithError:)]) { + [delegate restClient:self loadMetadataFailedWithError:request.error]; + } + } else { + [self performSelectorInBackground:@selector(parseMetadataWithRequest:) withObject:request]; + } + + [requests removeObject:request]; +} + + +- (void)parseMetadataWithRequest:(DBRequest*)request { + NSAutoreleasePool* pool = [NSAutoreleasePool new]; + + NSDictionary* result = (NSDictionary*)[request resultJSON]; + DBMetadata* metadata = [[[DBMetadata alloc] initWithDictionary:result] autorelease]; + [self performSelectorOnMainThread:@selector(didParseMetadata:) withObject:metadata waitUntilDone:NO]; + + [pool drain]; +} + + +- (void)didParseMetadata:(DBMetadata*)metadata { + if ([delegate respondsToSelector:@selector(restClient:loadedMetadata:)]) { + [delegate restClient:self loadedMetadata:metadata]; + } +} + + +- (void)loadFile:(NSString *)path intoPath:(NSString *)destinationPath +{ + NSString* fullPath = [NSString stringWithFormat:@"/files/%@%@", root, path]; + + NSURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTPS host:kDBDropboxAPIContentHost path:fullPath parameters:nil]; + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidLoadFile:)] + autorelease]; + request.resultFilename = destinationPath; + request.downloadProgressSelector = @selector(requestLoadProgress:); + request.userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + root, @"root", + path, @"path", + destinationPath, @"destinationPath", nil]; + [loadRequests setObject:request forKey:path]; +} + + +- (void)cancelFileLoad:(NSString*)path { + DBRequest* outstandingRequest = [loadRequests objectForKey:path]; + if (outstandingRequest) { + [outstandingRequest cancel]; + [loadRequests removeObjectForKey:path]; + } +} + + +- (void)requestLoadProgress:(DBRequest*)request { + if ([delegate respondsToSelector:@selector(restClient:loadProgress:forFile:)]) { + [delegate restClient:self loadProgress:request.downloadProgress forFile:request.resultFilename]; + } +} + + +- (void)restClient:(DBRestClient*)restClient loadedFile:(NSString*)destPath +contentType:(NSString*)contentType eTag:(NSString*)eTag { + // Empty selector to get the signature from +} + +- (void)requestDidLoadFile:(DBRequest*)request { + NSString* path = [request.userInfo objectForKey:@"path"]; + + if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:loadFileFailedWithError:)]) { + [delegate restClient:self loadFileFailedWithError:request.error]; + } + } else { + NSString* filename = request.resultFilename; + NSDictionary* headers = [request.response allHeaderFields]; + NSString* contentType = [headers objectForKey:@"Content-Type"]; + NSString* eTag = [headers objectForKey:@"Etag"]; + if ([delegate respondsToSelector:@selector(restClient:loadedFile:)]) { + [delegate restClient:self loadedFile:filename]; + } else if ([delegate respondsToSelector:@selector(restClient:loadedFile:contentType:)]) { + [delegate restClient:self loadedFile:filename contentType:contentType]; + } else if ([delegate respondsToSelector:@selector(restClient:loadedFile:contentType:eTag:)]) { + // This code is for the official Dropbox client to get eTag information from the server + NSMethodSignature* signature = + [self methodSignatureForSelector:@selector(restClient:loadedFile:contentType:eTag:)]; + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; + [invocation setTarget:delegate]; + [invocation setSelector:@selector(restClient:loadedFile:contentType:eTag:)]; + [invocation setArgument:&self atIndex:2]; + [invocation setArgument:&filename atIndex:3]; + [invocation setArgument:&contentType atIndex:4]; + [invocation setArgument:&eTag atIndex:5]; + [invocation invoke]; + } + } + + [loadRequests removeObjectForKey:path]; +} + + + +- (void)loadThumbnail:(NSString *)path ofSize:(NSString *)size intoPath:(NSString *)destinationPath +{ + NSString* fullPath = [NSString stringWithFormat:@"/thumbnails/%@%@", root, path]; + NSDictionary *params = nil; + + if(size) { + params = [NSDictionary dictionaryWithObjectsAndKeys: size, @"size", nil]; + } + + NSURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTP host:kDBDropboxAPIContentHost path:fullPath parameters:params]; + + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidLoadThumbnail:)] + autorelease]; + + request.resultFilename = destinationPath; + request.userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + root, @"root", + path, @"path", + destinationPath, @"destinationPath", nil]; + [requests addObject:request]; +} + + + +- (void)requestDidLoadThumbnail:(DBRequest*)request +{ + if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:loadThumbnailFailedWithError:)]) { + [delegate restClient:self loadThumbnailFailedWithError:request.error]; + } + } else { + if ([delegate respondsToSelector:@selector(restClient:loadedThumbnail:)]) { + [delegate restClient:self loadedThumbnail:request.resultFilename]; + } + } + + [requests removeObject:request]; +} + + + + +NSString *createFakeSignature(DBSession *session, NSArray *params, NSString *filename, NSURL *baseUrl) +{ + NSArray* extraParams = [MPURLRequestParameter parametersFromDictionary: + [NSDictionary dictionaryWithObject:filename forKey:@"file"]]; + + NSMutableArray* paramList = [NSMutableArray arrayWithArray:params]; + [paramList addObjectsFromArray:extraParams]; + [paramList sortUsingSelector:@selector(compare:)]; + NSString* paramString = [MPURLRequestParameter parameterStringForParameters:paramList]; + + MPOAuthURLRequest* oauthRequest = + [[[MPOAuthURLRequest alloc] initWithURL:baseUrl andParameters:paramList] autorelease]; + oauthRequest.HTTPMethod = @"POST"; + MPOAuthSignatureParameter *signatureParameter = + [[[MPOAuthSignatureParameter alloc] + initWithText:paramString andSecret:session.credentialStore.signingKey + forRequest:oauthRequest usingMethod:session.credentialStore.signatureMethod] + autorelease]; + + return [signatureParameter URLEncodedParameterString]; +} + +NSMutableURLRequest *createRealRequest(DBSession *session, NSArray *params, NSString *urlString, NSString *signatureText) +{ + NSMutableArray *paramList = [NSMutableArray arrayWithArray:params]; + // Then rebuild request using that signature + [paramList sortUsingSelector:@selector(compare:)]; + NSMutableString* realParamString = [[[NSMutableString alloc] initWithString: + [MPURLRequestParameter parameterStringForParameters:paramList]] + autorelease]; + [realParamString appendFormat:@"&%@", signatureText]; + + NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", urlString, realParamString]]; + NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url]; + urlRequest.HTTPMethod = @"POST"; + + return urlRequest; +} + +// Returns DBErrorNone if no errors were encountered +DBErrorCode addFileUploadToRequest(NSMutableURLRequest *urlRequest, NSString *filename, NSString *sourcePath) +{ + // Create input stream + CFUUIDRef uuid = CFUUIDCreate(NULL); + NSString* stringBoundary = [(NSString*)CFUUIDCreateString(NULL, uuid) autorelease]; + CFRelease(uuid); + + NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",stringBoundary]; + [urlRequest addValue:contentType forHTTPHeaderField: @"Content-Type"]; + + NSString* tempFilename = + [NSString stringWithFormat: @"%.0f.txt", [NSDate timeIntervalSinceReferenceDate] * 1000.0]; + NSString *tempFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:tempFilename]; + + //setting up the body + NSMutableData* bodyData = [NSMutableData data]; + [bodyData appendData: + [[NSString stringWithFormat:@"--%@\r\n", stringBoundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + + // Add data to upload + [bodyData appendData: + [[NSString stringWithFormat: + @"Content-Disposition: form-data; name=\"file\"; filename=\"%@\"\r\n", filename] + dataUsingEncoding:NSUTF8StringEncoding]]; + [bodyData appendData: + [[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] + dataUsingEncoding:NSUTF8StringEncoding]]; + + if (![[NSFileManager defaultManager] createFileAtPath:tempFilePath contents:bodyData attributes:nil]) { + NSLog(@"DBRestClient#uploadFileToRoot:path:filename:fromPath: failed to create file"); + return DBErrorGenericError; + } + + NSFileHandle* bodyFile = [NSFileHandle fileHandleForWritingAtPath:tempFilePath]; + [bodyFile seekToEndOfFile]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:sourcePath]) { + NSFileHandle* readFile = [NSFileHandle fileHandleForReadingAtPath:sourcePath]; + NSData* readData; + while ((readData = [readFile readDataOfLength:1024 * 512]) != nil && [readData length] > 0) { + @try { + [bodyFile writeData:readData]; + } @catch (NSException* e) { + NSLog(@"DBRestClient#uploadFileToRoot:path:filename:fromPath: failed to write data"); + [readFile closeFile]; + [bodyFile closeFile]; + [[NSFileManager defaultManager] removeItemAtPath:tempFilePath error:nil]; + return DBErrorInsufficientDiskSpace; + } + } + [readFile closeFile]; + } else { + NSLog(@"DBRestClient#uploadFileToRoot:path:filename:fromPath: unable to open sourceFile"); + } + + @try { + [bodyFile writeData: + [[NSString stringWithFormat:@"\r\n--%@--\r\n", stringBoundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + } @catch (NSException* e) { + NSLog(@"DBRestClient#uploadFileToRoot:path:filename:fromPath: failed to write end of data"); + [bodyFile closeFile]; + [[NSFileManager defaultManager] removeItemAtPath:tempFilePath error:nil]; + return DBErrorInsufficientDiskSpace; + } + + NSString* contentLength = [NSString stringWithFormat: @"%qu", [bodyFile offsetInFile]]; + [urlRequest addValue:contentLength forHTTPHeaderField: @"Content-Length"]; + [bodyFile closeFile]; + + urlRequest.HTTPBodyStream = [NSInputStream inputStreamWithFileAtPath:tempFilePath]; + + return DBErrorNone; +} + + + +- (void)uploadFile:(NSString*)filename toPath:(NSString*)path fromPath:(NSString *)sourcePath +{ + if (![[NSFileManager defaultManager] fileExistsAtPath:sourcePath]) { + NSDictionary* userInfo = [NSDictionary dictionaryWithObject:sourcePath forKey:@"sourcePath"]; + NSError* error = + [NSError errorWithDomain:DBErrorDomain code:DBErrorFileNotFound userInfo:userInfo]; + if ([delegate respondsToSelector:@selector(restClient:uploadFileFailedWithError:)]) { + [delegate restClient:self uploadFileFailedWithError:error]; + } + return; + } + + // path is the directory the file will be uploaded to, make sure it doesn't have a trailing / + // (unless it's the root dir) and is properly escaped + NSString* trimmedPath; + if ([path length] > 1 && [path characterAtIndex:[path length]-1] == '/') { + trimmedPath = [path substringToIndex:[path length]-1]; + } else { + trimmedPath = path; + } + NSString* escapedPath = [DBRestClient escapePath:trimmedPath]; + + NSString* urlString = [NSString stringWithFormat:@"%@://%@/%@/files/%@%@", + kDBProtocolHTTPS, kDBDropboxAPIContentHost, kDBDropboxAPIVersion, root, escapedPath]; + NSURL* baseUrl = [NSURL URLWithString:urlString]; + NSArray* params = [session.credentialStore oauthParameters]; + + NSString *escapedFilename = [filename stringByReplacingOccurrencesOfString:@";" withString:@"-"]; + + NSString *signatureText = createFakeSignature(session, params, escapedFilename, baseUrl); + + NSMutableURLRequest *urlRequest = createRealRequest(session, params, urlString, signatureText); + + DBErrorCode errorCode = addFileUploadToRequest(urlRequest, escapedFilename, sourcePath); + if(errorCode == DBErrorNone) { + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidUploadFile:)] + autorelease]; + request.uploadProgressSelector = @selector(requestUploadProgress:); + NSString* dropboxPath = [path stringByAppendingPathComponent:filename]; + request.userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + root, @"root", + path, @"path", + dropboxPath, @"destinationPath", + sourcePath, @"sourcePath", nil]; + [requests addObject:request]; + } else { + NSDictionary* userInfo = [NSDictionary dictionaryWithObject:sourcePath forKey:@"sourcePath"]; + NSError* error = + [NSError errorWithDomain:DBErrorDomain code:errorCode userInfo:userInfo]; + if ([delegate respondsToSelector:@selector(restClient:uploadFileFailedWithError:)]) { + [delegate restClient:self uploadFileFailedWithError:error]; + } + } +} + + +- (void)requestUploadProgress:(DBRequest*)request { + NSString* sourcePath = [(NSDictionary*)request.userInfo objectForKey:@"sourcePath"]; + NSString* destPath = [request.userInfo objectForKey:@"destinationPath"]; + + if ([delegate respondsToSelector:@selector(restClient:uploadProgress:forFile:from:)]) { + [delegate restClient:self uploadProgress:request.uploadProgress + forFile:destPath from:sourcePath]; + } else if ([delegate respondsToSelector:@selector(restClient:uploadProgress:forFile:)]) { + [delegate restClient:self uploadProgress:request.uploadProgress forFile:sourcePath]; + } +} + + +- (void)requestDidUploadFile:(DBRequest*)request { + if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:uploadFileFailedWithError:)]) { + [delegate restClient:self uploadFileFailedWithError:request.error]; + } + } else { + NSString* sourcePath = [(NSDictionary*)request.userInfo objectForKey:@"sourcePath"]; + NSString* destPath = [request.userInfo objectForKey:@"destinationPath"]; + if ([delegate respondsToSelector:@selector(restClient:uploadedFile:from:)]) { + [delegate restClient:self uploadedFile:destPath from:sourcePath]; + } else if ([delegate respondsToSelector:@selector(restClient:uploadedFile:)]) { + [delegate restClient:self uploadedFile:sourcePath]; + } + } + + [requests removeObject:request]; +} + + + +- (void)moveFrom:(NSString*)from_path toPath:(NSString *)to_path +{ + NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: + root, @"root", + from_path, @"from_path", + to_path, @"to_path", nil]; + + NSMutableURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTP host:kDBDropboxAPIHost path:@"/fileops/move" + parameters:params method:@"POST"]; + + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidMovePath:)] + autorelease]; + + request.userInfo = params; + [requests addObject:request]; +} + + + +- (void)requestDidMovePath:(DBRequest*)request { + if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:movePathFailedWithError:)]) { + [delegate restClient:self movePathFailedWithError:request.error]; + } + } else { + NSDictionary *params = (NSDictionary *)request.userInfo; + + if ([delegate respondsToSelector:@selector(restClient:movedPath:toPath:)]) { + [delegate restClient:self movedPath:[params valueForKey:@"from_path"] + toPath:[params valueForKey:@"to_path"]]; + } + } + + [requests removeObject:request]; +} + + +- (void)copyFrom:(NSString*)from_path toPath:(NSString *)to_path +{ + NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: + root, @"root", + from_path, @"from_path", + to_path, @"to_path", nil]; + + NSMutableURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTP host:kDBDropboxAPIHost path:@"/fileops/copy" + parameters:params method:@"POST"]; + + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidCopyPath:)] + autorelease]; + + request.userInfo = params; + [requests addObject:request]; +} + + + +- (void)requestDidCopyPath:(DBRequest*)request { + if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:copyPathFailedWithError:)]) { + [delegate restClient:self copyPathFailedWithError:request.error]; + } + } else { + NSDictionary *params = (NSDictionary *)request.userInfo; + + if ([delegate respondsToSelector:@selector(restClient:copiedPath:toPath:)]) { + [delegate restClient:self copiedPath:[params valueForKey:@"from_path"] + toPath:[params valueForKey:@"to_path"]]; + } + } + + [requests removeObject:request]; +} + + +- (void)deletePath:(NSString*)path +{ + NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: + root, @"root", + path, @"path", nil]; + + NSMutableURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTP host:kDBDropboxAPIHost path:@"/fileops/delete" + parameters:params method:@"POST"]; + + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidDeletePath:)] + autorelease]; + + request.userInfo = params; + [requests addObject:request]; +} + + + +- (void)requestDidDeletePath:(DBRequest*)request { + if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:deletePathFailedWithError:)]) { + [delegate restClient:self deletePathFailedWithError:request.error]; + } + } else { + if ([delegate respondsToSelector:@selector(restClient:deletedPath:)]) { + NSString* path = [request.userInfo objectForKey:@"path"]; + [delegate restClient:self deletedPath:path]; + } + } + + [requests removeObject:request]; +} + + + + +- (void)createFolder:(NSString*)path +{ + NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: + root, @"root", + path, @"path", nil]; + + NSString* fullPath = @"/fileops/create_folder"; + NSMutableURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTP host:kDBDropboxAPIHost path:fullPath + parameters:params method:@"POST"]; + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidCreateDirectory:)] + autorelease]; + request.userInfo = params; + [requests addObject:request]; +} + + + +- (void)requestDidCreateDirectory:(DBRequest*)request { + if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:createFolderFailedWithError:)]) { + [delegate restClient:self createFolderFailedWithError:request.error]; + } + } else { + NSDictionary* result = (NSDictionary*)[request resultJSON]; + DBMetadata* metadata = [[[DBMetadata alloc] initWithDictionary:result] autorelease]; + if ([delegate respondsToSelector:@selector(restClient:createdFolder:)]) { + [delegate restClient:self createdFolder:metadata]; + } + } + + [requests removeObject:request]; +} + + + +- (void)loadAccountInfo +{ + NSURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTP host:kDBDropboxAPIHost path:@"/account/info" parameters:nil]; + + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidLoadAccountInfo:)] + autorelease]; + + request.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:root, @"root", nil]; + + [requests addObject:request]; +} + + +- (void)requestDidLoadAccountInfo:(DBRequest*)request +{ + if (request.error) { + [self checkForAuthenticationFailure:request]; + if ([delegate respondsToSelector:@selector(restClient:loadAccountInfoFailedWithError:)]) { + [delegate restClient:self loadAccountInfoFailedWithError:request.error]; + } + } else { + NSDictionary* result = (NSDictionary*)[request resultJSON]; + DBAccountInfo* accountInfo = [[[DBAccountInfo alloc] initWithDictionary:result] autorelease]; + if ([delegate respondsToSelector:@selector(restClient:loadedAccountInfo:)]) { + [delegate restClient:self loadedAccountInfo:accountInfo]; + } + } + + [requests removeObject:request]; +} + +- (void)createAccount:(NSString *)email password:(NSString *)password firstName:(NSString *)firstName lastName:(NSString *)lastName +{ + NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: + email, @"email", + password, @"password", + firstName, @"first_name", + lastName, @"last_name", nil]; + + NSString* fullPath = @"/account"; + NSMutableURLRequest* urlRequest = + [self requestWithProtocol:kDBProtocolHTTPS host:kDBDropboxAPIHost path:fullPath + parameters:params method:@"POST"]; + + DBRequest* request = + [[[DBRequest alloc] + initWithURLRequest:urlRequest andInformTarget:self selector:@selector(requestDidCreateAccount:)] + autorelease]; + + request.userInfo = params; + + [requests addObject:request]; +} + +- (void)requestDidCreateAccount:(DBRequest *)request +{ + if(request.error) { + if([delegate respondsToSelector:@selector(restClient:createAccountFailedWithError:)]) { + [delegate restClient:self createAccountFailedWithError:request.error]; + } + } else { + if ([delegate respondsToSelector:@selector(restClientCreatedAccount:)]) { + [delegate restClientCreatedAccount:self]; + } + } + + [requests removeObject:request]; +} + + +#pragma mark private methods + ++ (NSString*)escapePath:(NSString*)path { + CFStringEncoding encoding = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding); + NSString *escapedPath = + (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)path, + NULL, + (CFStringRef)@":?=,!$&'()*+;[]@#~", + encoding); + + return [escapedPath autorelease]; +} + + +- (NSMutableURLRequest*)requestWithProtocol:(NSString*)protocol host:(NSString*)host path:(NSString*)path + parameters:(NSDictionary*)params { + + return [self requestWithProtocol:protocol host:host path:path parameters:params method:nil]; +} + + +- (NSMutableURLRequest*)requestWithProtocol:(NSString*)protocol host:(NSString*)host path:(NSString*)path + parameters:(NSDictionary*)params method:(NSString*)method { + + NSString* escapedPath = [DBRestClient escapePath:path]; + NSString* urlString = [NSString stringWithFormat:@"%@://%@/%@%@", + protocol, host, kDBDropboxAPIVersion, escapedPath]; + NSURL* url = [NSURL URLWithString:urlString]; + + NSArray* paramList = [session.credentialStore oauthParameters]; + if ([params count] > 0) { + NSArray* extraParams = [MPURLRequestParameter parametersFromDictionary:params]; + paramList = [paramList arrayByAddingObjectsFromArray:extraParams]; + } + MPOAuthURLRequest* oauthRequest = + [[[MPOAuthURLRequest alloc] initWithURL:url andParameters:paramList] autorelease]; + if (method) { + oauthRequest.HTTPMethod = method; + } + NSMutableURLRequest* urlRequest = [oauthRequest + urlRequestSignedWithSecret:session.credentialStore.signingKey + usingMethod:session.credentialStore.signatureMethod]; + return urlRequest; +} + + +- (void)checkForAuthenticationFailure:(DBRequest*)request { + if (request.error && request.error.code == 401 && [request.error.domain isEqual:@"dropbox.com"]) { + [session.delegate sessionDidReceiveAuthorizationFailure:session]; + } +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBSession.h b/Classes/ThirdParty/DropboxSDK/DBSession.h new file mode 100644 index 0000000..599a903 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBSession.h @@ -0,0 +1,44 @@ +// +// DBSession.h +// DropboxSDK +// +// Created by Brian Smith on 4/8/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "MPOAuthCredentialConcreteStore.h" + +extern NSString* kDBDropboxAPIHost; +extern NSString* kDBDropboxAPIContentHost; +extern NSString* kDBDropboxAPIVersion; + +@protocol DBSessionDelegate; + + +/* Creating and setting the shared DBSession should be done before any other Dropbox objects are + used, perferrably in the UIApplication delegate. */ +@interface DBSession : NSObject { + MPOAuthCredentialConcreteStore* credentialStore; + id delegate; +} + ++ (DBSession*)sharedSession; ++ (void)setSharedSession:(DBSession*)session; + +- (id)initWithConsumerKey:(NSString*)key consumerSecret:(NSString*)secret; +- (BOOL)isLinked; // If not linked, you can only call loginWithEmail:password from the DBRestClient + +- (void)updateAccessToken:(NSString*)token accessTokenSecret:(NSString*)secret; +- (void)unlink; + +@property (nonatomic, readonly) MPOAuthCredentialConcreteStore* credentialStore; +@property (nonatomic, assign) id delegate; + +@end + + +@protocol DBSessionDelegate + +- (void)sessionDidReceiveAuthorizationFailure:(DBSession*)session; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DBSession.m b/Classes/ThirdParty/DropboxSDK/DBSession.m new file mode 100644 index 0000000..af16ccd --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DBSession.m @@ -0,0 +1,117 @@ +// +// DBSession.m +// DropboxSDK +// +// Created by Brian Smith on 4/8/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "DBSession.h" +#import "MPOAuthCredentialConcreteStore.h" +#import "MPOAuthSignatureParameter.h" + + +NSString* kDBDropboxAPIHost = @"api.dropbox.com"; +NSString* kDBDropboxAPIContentHost = @"api-content.dropbox.com"; +NSString* kDBDropboxAPIVersion = @"0"; + +static DBSession* _sharedSession = nil; +static NSString* kDBDropboxSavedCredentialsKey = @"kDBDropboxSavedCredentialsKey"; + + +@interface DBSession () + +- (NSDictionary*)savedCredentials; +- (void)saveCredentials:(NSDictionary*)credentials; +- (void)clearSavedCredentials; + +@end + + +@implementation DBSession + ++ (DBSession*)sharedSession { + return _sharedSession; +} + ++ (void)setSharedSession:(DBSession*)session { + if (session == _sharedSession) return; + [_sharedSession release]; + _sharedSession = [session retain]; +} + +- (id)initWithConsumerKey:(NSString*)key consumerSecret:(NSString*)secret { + if ((self = [super init])) { + + NSMutableDictionary* credentials = + [NSMutableDictionary dictionaryWithObjectsAndKeys: + key, kMPOAuthCredentialConsumerKey, + secret, kMPOAuthCredentialConsumerSecret, + kMPOAuthSignatureMethodHMACSHA1, kMPOAuthSignatureMethod, nil]; + + NSDictionary* savedCredentials = [self savedCredentials]; + if (savedCredentials != nil) { + if ([key isEqualToString:[savedCredentials objectForKey:kMPOAuthCredentialConsumerKey]]) { + + [credentials setObject:[savedCredentials objectForKey:kMPOAuthCredentialAccessToken] + forKey:kMPOAuthCredentialAccessToken]; + [credentials setObject:[savedCredentials objectForKey:kMPOAuthCredentialAccessTokenSecret] + forKey:kMPOAuthCredentialAccessTokenSecret]; + } else { + [self clearSavedCredentials]; + } + } + + credentialStore = [[MPOAuthCredentialConcreteStore alloc] initWithCredentials:credentials]; + } + return self; +} + +- (void)dealloc { + [credentialStore release]; + [super dealloc]; +} + +@synthesize credentialStore; +@synthesize delegate; + +- (void)updateAccessToken:(NSString*)token accessTokenSecret:(NSString*)secret { + credentialStore.accessToken = token; + credentialStore.accessTokenSecret = secret; + NSDictionary* credentials = [NSDictionary dictionaryWithObjectsAndKeys: + credentialStore.consumerKey, kMPOAuthCredentialConsumerKey, + credentialStore.accessToken, kMPOAuthCredentialAccessToken, + credentialStore.accessTokenSecret, kMPOAuthCredentialAccessTokenSecret, + nil]; + [self saveCredentials:credentials]; +} + +- (BOOL) isLinked { + return credentialStore.accessToken != nil; +} + +- (void)unlink { + credentialStore.accessToken = nil; + credentialStore.accessTokenSecret = nil; + [self clearSavedCredentials]; +} + +#pragma mark private methods + +- (NSDictionary*)savedCredentials { + return [[NSUserDefaults standardUserDefaults] objectForKey:kDBDropboxSavedCredentialsKey]; +} + +- (void)saveCredentials:(NSDictionary*)credentials { + if (credentials == nil) return; + + [[NSUserDefaults standardUserDefaults] + setObject:credentials forKey:kDBDropboxSavedCredentialsKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)clearSavedCredentials { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:kDBDropboxSavedCredentialsKey]; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/DropboxSDK.h b/Classes/ThirdParty/DropboxSDK/DropboxSDK.h new file mode 100644 index 0000000..4973d62 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/DropboxSDK.h @@ -0,0 +1,17 @@ +/* + * DropboxSDK.h + * DropboxSDK + * + * Created by Brian Smith on 7/13/10. + * Copyright 2010 Dropbox, Inc. All rights reserved. + * + */ + +/* Import this file to get the most important header files imported */ +#import "DBSession.h" +#import "DBRestClient.h" +#import "DBLoginController.h" +#import "DBAccountInfo.h" +#import "DBMetadata.h" +#import "DBQuota.h" +#import "DBError.h" \ No newline at end of file diff --git a/Classes/ThirdParty/DropboxSDK/JSON/JSON.h b/Classes/ThirdParty/DropboxSDK/JSON/JSON.h new file mode 100644 index 0000000..1e58c9a --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/JSON.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @mainpage A strict JSON parser and generator for Objective-C + + JSON (JavaScript Object Notation) is a lightweight data-interchange + format. This framework provides two apis for parsing and generating + JSON. One standard object-based and a higher level api consisting of + categories added to existing Objective-C classes. + + Learn more on the http://code.google.com/p/json-framework project site. + + This framework does its best to be as strict as possible, both in what it + accepts and what it generates. For example, it does not support trailing commas + in arrays or objects. Nor does it support embedded comments, or + anything else not in the JSON specification. This is considered a feature. + +*/ + +#import "SBJSON.h" +#import "NSObject+SBJSON.h" +#import "NSString+SBJSON.h" + diff --git a/Classes/ThirdParty/DropboxSDK/JSON/NSObject+SBJSON.h b/Classes/ThirdParty/DropboxSDK/JSON/NSObject+SBJSON.h new file mode 100644 index 0000000..ecf0ee4 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/NSObject+SBJSON.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + + +/** + @brief Adds JSON generation to Foundation classes + + This is a category on NSObject that adds methods for returning JSON representations + of standard objects to the objects themselves. This means you can call the + -JSONRepresentation method on an NSArray object and it'll do what you want. + */ +@interface NSObject (NSObject_SBJSON) + +/** + @brief Returns a string containing the receiver encoded as a JSON fragment. + + This method is added as a category on NSObject but is only actually + supported for the following objects: + @li NSDictionary + @li NSArray + @li NSString + @li NSNumber (also used for booleans) + @li NSNull + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString *)JSONFragment; + +/** + @brief Returns a string containing the receiver encoded in JSON. + + This method is added as a category on NSObject but is only actually + supported for the following objects: + @li NSDictionary + @li NSArray + */ +- (NSString *)JSONRepresentation; + +@end + diff --git a/Classes/ThirdParty/DropboxSDK/JSON/NSObject+SBJSON.m b/Classes/ThirdParty/DropboxSDK/JSON/NSObject+SBJSON.m new file mode 100644 index 0000000..20b084b --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/NSObject+SBJSON.m @@ -0,0 +1,53 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "NSObject+SBJSON.h" +#import "SBJsonWriter.h" + +@implementation NSObject (NSObject_SBJSON) + +- (NSString *)JSONFragment { + SBJsonWriter *jsonWriter = [SBJsonWriter new]; + NSString *json = [jsonWriter stringWithFragment:self]; + if (!json) + NSLog(@"-JSONFragment failed. Error trace is: %@", [jsonWriter errorTrace]); + [jsonWriter release]; + return json; +} + +- (NSString *)JSONRepresentation { + SBJsonWriter *jsonWriter = [SBJsonWriter new]; + NSString *json = [jsonWriter stringWithObject:self]; + if (!json) + NSLog(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]); + [jsonWriter release]; + return json; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/JSON/NSString+SBJSON.h b/Classes/ThirdParty/DropboxSDK/JSON/NSString+SBJSON.h new file mode 100644 index 0000000..fad7179 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/NSString+SBJSON.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +/** + @brief Adds JSON parsing methods to NSString + +This is a category on NSString that adds methods for parsing the target string. +*/ +@interface NSString (NSString_SBJSON) + + +/** + @brief Returns the object represented in the receiver, or nil on error. + + Returns a a scalar object represented by the string's JSON fragment representation. + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)JSONFragmentValue; + +/** + @brief Returns the NSDictionary or NSArray represented by the current string's JSON representation. + + Returns the dictionary or array represented in the receiver, or nil on error. + + Returns the NSDictionary or NSArray represented by the current string's JSON representation. + */ +- (id)JSONValue; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/JSON/NSString+SBJSON.m b/Classes/ThirdParty/DropboxSDK/JSON/NSString+SBJSON.m new file mode 100644 index 0000000..41a5a85 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/NSString+SBJSON.m @@ -0,0 +1,55 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "NSString+SBJSON.h" +#import "SBJsonParser.h" + +@implementation NSString (NSString_SBJSON) + +- (id)JSONFragmentValue +{ + SBJsonParser *jsonParser = [SBJsonParser new]; + id repr = [jsonParser fragmentWithString:self]; + if (!repr) + NSLog(@"-JSONFragmentValue failed. Error trace is: %@", [jsonParser errorTrace]); + [jsonParser release]; + return repr; +} + +- (id)JSONValue +{ + SBJsonParser *jsonParser = [SBJsonParser new]; + id repr = [jsonParser objectWithString:self]; + if (!repr) + NSLog(@"-JSONValue failed. Error trace is: %@", [jsonParser errorTrace]); + [jsonParser release]; + return repr; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/JSON/SBJSON.h b/Classes/ThirdParty/DropboxSDK/JSON/SBJSON.h new file mode 100644 index 0000000..43d63c3 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/SBJSON.h @@ -0,0 +1,75 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonParser.h" +#import "SBJsonWriter.h" + +/** + @brief Facade for SBJsonWriter/SBJsonParser. + + Requests are forwarded to instances of SBJsonWriter and SBJsonParser. + */ +@interface SBJSON : SBJsonBase { + +@private + SBJsonParser *jsonParser; + SBJsonWriter *jsonWriter; +} + + +/// Return the fragment represented by the given string +- (id)fragmentWithString:(NSString*)jsonrep + error:(NSError**)error; + +/// Return the object represented by the given string +- (id)objectWithString:(NSString*)jsonrep + error:(NSError**)error; + +/// Parse the string and return the represented object (or scalar) +- (id)objectWithString:(id)value + allowScalar:(BOOL)x + error:(NSError**)error; + + +/// Return JSON representation of an array or dictionary +- (NSString*)stringWithObject:(id)value + error:(NSError**)error; + +/// Return JSON representation of any legal JSON value +- (NSString*)stringWithFragment:(id)value + error:(NSError**)error; + +/// Return JSON representation (or fragment) for the given object +- (NSString*)stringWithObject:(id)value + allowScalar:(BOOL)x + error:(NSError**)error; + + +@end diff --git a/Classes/ThirdParty/DropboxSDK/JSON/SBJSON.m b/Classes/ThirdParty/DropboxSDK/JSON/SBJSON.m new file mode 100644 index 0000000..2a30f1a --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/SBJSON.m @@ -0,0 +1,212 @@ +/* + Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJSON.h" + +@implementation SBJSON + +- (id)init { + self = [super init]; + if (self) { + jsonWriter = [SBJsonWriter new]; + jsonParser = [SBJsonParser new]; + [self setMaxDepth:512]; + + } + return self; +} + +- (void)dealloc { + [jsonWriter release]; + [jsonParser release]; + [super dealloc]; +} + +#pragma mark Writer + + +- (NSString *)stringWithObject:(id)obj { + NSString *repr = [jsonWriter stringWithObject:obj]; + if (repr) + return repr; + + [errorTrace release]; + errorTrace = [[jsonWriter errorTrace] mutableCopy]; + return nil; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + @param allowScalar wether to return json fragments for scalar objects + @param error used to return an error by reference (pass NULL if this is not desired) + +@deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString*)stringWithObject:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { + + NSString *json = allowScalar ? [jsonWriter stringWithFragment:value] : [jsonWriter stringWithObject:value]; + if (json) + return json; + + [errorTrace release]; + errorTrace = [[jsonWriter errorTrace] mutableCopy]; + + if (error) + *error = [errorTrace lastObject]; + return nil; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (NSString*)stringWithFragment:(id)value error:(NSError**)error { + return [self stringWithObject:value + allowScalar:YES + error:error]; +} + +/** + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p error can be interrogated to find the cause of the error. + + @param value a NSDictionary or NSArray instance + @param error used to return an error by reference (pass NULL if this is not desired) + */ +- (NSString*)stringWithObject:(id)value error:(NSError**)error { + return [self stringWithObject:value + allowScalar:NO + error:error]; +} + +#pragma mark Parsing + +- (id)objectWithString:(NSString *)repr { + id obj = [jsonParser objectWithString:repr]; + if (obj) + return obj; + + [errorTrace release]; + errorTrace = [[jsonParser errorTrace] mutableCopy]; + + return nil; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param value the json string to parse + @param allowScalar whether to return objects for JSON fragments + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)objectWithString:(id)value allowScalar:(BOOL)allowScalar error:(NSError**)error { + + id obj = allowScalar ? [jsonParser fragmentWithString:value] : [jsonParser objectWithString:value]; + if (obj) + return obj; + + [errorTrace release]; + errorTrace = [[jsonParser errorTrace] mutableCopy]; + + if (error) + *error = [errorTrace lastObject]; + return nil; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param repr the json string to parse + @param error used to return an error by reference (pass NULL if this is not desired) + + @deprecated Given we bill ourselves as a "strict" JSON library, this method should be removed. + */ +- (id)fragmentWithString:(NSString*)repr error:(NSError**)error { + return [self objectWithString:repr + allowScalar:YES + error:error]; +} + +/** + Returns the object represented by the passed-in string or nil on error. The returned object + will be either a dictionary or an array. + + @param repr the json string to parse + @param error used to return an error by reference (pass NULL if this is not desired) + */ +- (id)objectWithString:(NSString*)repr error:(NSError**)error { + return [self objectWithString:repr + allowScalar:NO + error:error]; +} + + + +#pragma mark Properties - parsing + +- (NSUInteger)maxDepth { + return jsonParser.maxDepth; +} + +- (void)setMaxDepth:(NSUInteger)d { + jsonWriter.maxDepth = jsonParser.maxDepth = d; +} + + +#pragma mark Properties - writing + +- (BOOL)humanReadable { + return jsonWriter.humanReadable; +} + +- (void)setHumanReadable:(BOOL)x { + jsonWriter.humanReadable = x; +} + +- (BOOL)sortKeys { + return jsonWriter.sortKeys; +} + +- (void)setSortKeys:(BOOL)x { + jsonWriter.sortKeys = x; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/JSON/SBJsonBase.h b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonBase.h new file mode 100644 index 0000000..7b10844 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonBase.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +extern NSString * SBJSONErrorDomain; + + +enum { + EUNSUPPORTED = 1, + EPARSENUM, + EPARSE, + EFRAGMENT, + ECTRL, + EUNICODE, + EDEPTH, + EESCAPE, + ETRAILCOMMA, + ETRAILGARBAGE, + EEOF, + EINPUT +}; + +/** + @brief Common base class for parsing & writing. + + This class contains the common error-handling code and option between the parser/writer. + */ +@interface SBJsonBase : NSObject { + NSMutableArray *errorTrace; + +@protected + NSUInteger depth, maxDepth; +} + +/** + @brief The maximum recursing depth. + + Defaults to 512. If the input is nested deeper than this the input will be deemed to be + malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can + turn off this security feature by setting the maxDepth value to 0. + */ +@property NSUInteger maxDepth; + +/** + @brief Return an error trace, or nil if there was no errors. + + Note that this method returns the trace of the last method that failed. + You need to check the return value of the call you're making to figure out + if the call actually failed, before you know call this method. + */ + @property(copy,readonly) NSArray* errorTrace; + +/// @internal for use in subclasses to add errors to the stack trace +- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str; + +/// @internal for use in subclasess to clear the error before a new parsing attempt +- (void)clearErrorTrace; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/JSON/SBJsonBase.m b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonBase.m new file mode 100644 index 0000000..6684325 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonBase.m @@ -0,0 +1,78 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonBase.h" +NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain"; + + +@implementation SBJsonBase + +@synthesize errorTrace; +@synthesize maxDepth; + +- (id)init { + self = [super init]; + if (self) + self.maxDepth = 512; + return self; +} + +- (void)dealloc { + [errorTrace release]; + [super dealloc]; +} + +- (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str { + NSDictionary *userInfo; + if (!errorTrace) { + errorTrace = [NSMutableArray new]; + userInfo = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey]; + + } else { + userInfo = [NSDictionary dictionaryWithObjectsAndKeys: + str, NSLocalizedDescriptionKey, + [errorTrace lastObject], NSUnderlyingErrorKey, + nil]; + } + + NSError *error = [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:userInfo]; + + [self willChangeValueForKey:@"errorTrace"]; + [errorTrace addObject:error]; + [self didChangeValueForKey:@"errorTrace"]; +} + +- (void)clearErrorTrace { + [self willChangeValueForKey:@"errorTrace"]; + [errorTrace release]; + errorTrace = nil; + [self didChangeValueForKey:@"errorTrace"]; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/JSON/SBJsonParser.h b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonParser.h new file mode 100644 index 0000000..e95304d --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonParser.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonBase.h" + +/** + @brief Options for the parser class. + + This exists so the SBJSON facade can implement the options in the parser without having to re-declare them. + */ +@protocol SBJsonParser + +/** + @brief Return the object represented by the given string. + + Returns the object represented by the passed-in string or nil on error. The returned object can be + a string, number, boolean, null, array or dictionary. + + @param repr the json string to parse + */ +- (id)objectWithString:(NSString *)repr; + +@end + + +/** + @brief The JSON parser class. + + JSON is mapped to Objective-C types in the following way: + + @li Null -> NSNull + @li String -> NSMutableString + @li Array -> NSMutableArray + @li Object -> NSMutableDictionary + @li Boolean -> NSNumber (initialised with -initWithBool:) + @li Number -> NSDecimalNumber + + Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber + instances. These are initialised with the -initWithBool: method, and + round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be + represented as 'true' and 'false' again.) + + JSON numbers turn into NSDecimalNumber instances, + as we can thus avoid any loss of precision. (JSON allows ridiculously large numbers.) + + */ +@interface SBJsonParser : SBJsonBase { + +@private + const char *c; +} + +@end + +// don't use - exists for backwards compatibility with 2.1.x only. Will be removed in 2.3. +@interface SBJsonParser (Private) +- (id)fragmentWithString:(id)repr; +@end + + diff --git a/Classes/ThirdParty/DropboxSDK/JSON/SBJsonParser.m b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonParser.m new file mode 100644 index 0000000..eda051a --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonParser.m @@ -0,0 +1,475 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonParser.h" + +@interface SBJsonParser () + +- (BOOL)scanValue:(NSObject **)o; + +- (BOOL)scanRestOfArray:(NSMutableArray **)o; +- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o; +- (BOOL)scanRestOfNull:(NSNull **)o; +- (BOOL)scanRestOfFalse:(NSNumber **)o; +- (BOOL)scanRestOfTrue:(NSNumber **)o; +- (BOOL)scanRestOfString:(NSMutableString **)o; + +// Cannot manage without looking at the first digit +- (BOOL)scanNumber:(NSNumber **)o; + +- (BOOL)scanHexQuad:(unichar *)x; +- (BOOL)scanUnicodeChar:(unichar *)x; + +- (BOOL)scanIsAtEnd; + +@end + +#define skipWhitespace(c) while (isspace(*c)) c++ +#define skipDigits(c) while (isdigit(*c)) c++ + + +@implementation SBJsonParser + +static char ctrl[0x22]; + + ++ (void)initialize { + ctrl[0] = '\"'; + ctrl[1] = '\\'; + for (int i = 1; i < 0x20; i++) + ctrl[i+1] = i; + ctrl[0x21] = 0; +} + +/** + @deprecated This exists in order to provide fragment support in older APIs in one more version. + It should be removed in the next major version. + */ +- (id)fragmentWithString:(id)repr { + [self clearErrorTrace]; + + if (!repr) { + [self addErrorWithCode:EINPUT description:@"Input was 'nil'"]; + return nil; + } + + depth = 0; + c = [repr UTF8String]; + + id o; + if (![self scanValue:&o]) { + return nil; + } + + // We found some valid JSON. But did it also contain something else? + if (![self scanIsAtEnd]) { + [self addErrorWithCode:ETRAILGARBAGE description:@"Garbage after JSON"]; + return nil; + } + + NSAssert1(o, @"Should have a valid object from %@", repr); + return o; +} + +- (id)objectWithString:(NSString *)repr { + + id o = [self fragmentWithString:repr]; + if (!o) + return nil; + + // Check that the object we've found is a valid JSON container. + if (![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) { + [self addErrorWithCode:EFRAGMENT description:@"Valid fragment, but not JSON"]; + return nil; + } + + return o; +} + +/* + In contrast to the public methods, it is an error to omit the error parameter here. + */ +- (BOOL)scanValue:(NSObject **)o +{ + skipWhitespace(c); + + switch (*c++) { + case '{': + return [self scanRestOfDictionary:(NSMutableDictionary **)o]; + break; + case '[': + return [self scanRestOfArray:(NSMutableArray **)o]; + break; + case '"': + return [self scanRestOfString:(NSMutableString **)o]; + break; + case 'f': + return [self scanRestOfFalse:(NSNumber **)o]; + break; + case 't': + return [self scanRestOfTrue:(NSNumber **)o]; + break; + case 'n': + return [self scanRestOfNull:(NSNull **)o]; + break; + case '-': + case '0'...'9': + c--; // cannot verify number correctly without the first character + return [self scanNumber:(NSNumber **)o]; + break; + case '+': + [self addErrorWithCode:EPARSENUM description: @"Leading + disallowed in number"]; + return NO; + break; + case 0x0: + [self addErrorWithCode:EEOF description:@"Unexpected end of string"]; + return NO; + break; + default: + [self addErrorWithCode:EPARSE description: @"Unrecognised leading character"]; + return NO; + break; + } + + NSAssert(0, @"Should never get here"); + return NO; +} + +- (BOOL)scanRestOfTrue:(NSNumber **)o +{ + if (!strncmp(c, "rue", 3)) { + c += 3; + *o = [NSNumber numberWithBool:YES]; + return YES; + } + [self addErrorWithCode:EPARSE description:@"Expected 'true'"]; + return NO; +} + +- (BOOL)scanRestOfFalse:(NSNumber **)o +{ + if (!strncmp(c, "alse", 4)) { + c += 4; + *o = [NSNumber numberWithBool:NO]; + return YES; + } + [self addErrorWithCode:EPARSE description: @"Expected 'false'"]; + return NO; +} + +- (BOOL)scanRestOfNull:(NSNull **)o { + if (!strncmp(c, "ull", 3)) { + c += 3; + *o = [NSNull null]; + return YES; + } + [self addErrorWithCode:EPARSE description: @"Expected 'null'"]; + return NO; +} + +- (BOOL)scanRestOfArray:(NSMutableArray **)o { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + + *o = [NSMutableArray arrayWithCapacity:8]; + + for (; *c ;) { + id v; + + skipWhitespace(c); + if (*c == ']' && c++) { + depth--; + return YES; + } + + if (![self scanValue:&v]) { + [self addErrorWithCode:EPARSE description:@"Expected value while parsing array"]; + return NO; + } + + [*o addObject:v]; + + skipWhitespace(c); + if (*c == ',' && c++) { + skipWhitespace(c); + if (*c == ']') { + [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in array"]; + return NO; + } + } + } + + [self addErrorWithCode:EEOF description: @"End of input while parsing array"]; + return NO; +} + +- (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o +{ + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + + *o = [NSMutableDictionary dictionaryWithCapacity:7]; + + for (; *c ;) { + id k, v; + + skipWhitespace(c); + if (*c == '}' && c++) { + depth--; + return YES; + } + + if (!(*c == '\"' && c++ && [self scanRestOfString:&k])) { + [self addErrorWithCode:EPARSE description: @"Object key string expected"]; + return NO; + } + + skipWhitespace(c); + if (*c != ':') { + [self addErrorWithCode:EPARSE description: @"Expected ':' separating key and value"]; + return NO; + } + + c++; + if (![self scanValue:&v]) { + NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k]; + [self addErrorWithCode:EPARSE description: string]; + return NO; + } + + [*o setObject:v forKey:k]; + + skipWhitespace(c); + if (*c == ',' && c++) { + skipWhitespace(c); + if (*c == '}') { + [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in object"]; + return NO; + } + } + } + + [self addErrorWithCode:EEOF description: @"End of input while parsing object"]; + return NO; +} + +- (BOOL)scanRestOfString:(NSMutableString **)o +{ + *o = [NSMutableString stringWithCapacity:16]; + do { + // First see if there's a portion we can grab in one go. + // Doing this caused a massive speedup on the long string. + size_t len = strcspn(c, ctrl); + if (len) { + // check for + id t = [[NSString alloc] initWithBytesNoCopy:(char*)c + length:len + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + if (t) { + [*o appendString:t]; + [t release]; + c += len; + } + } + + if (*c == '"') { + c++; + return YES; + + } else if (*c == '\\') { + unichar uc = *++c; + switch (uc) { + case '\\': + case '/': + case '"': + break; + + case 'b': uc = '\b'; break; + case 'n': uc = '\n'; break; + case 'r': uc = '\r'; break; + case 't': uc = '\t'; break; + case 'f': uc = '\f'; break; + + case 'u': + c++; + if (![self scanUnicodeChar:&uc]) { + [self addErrorWithCode:EUNICODE description: @"Broken unicode character"]; + return NO; + } + c--; // hack. + break; + default: + [self addErrorWithCode:EESCAPE description: [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]]; + return NO; + break; + } + CFStringAppendCharacters((CFMutableStringRef)*o, &uc, 1); + c++; + + } else if (*c < 0x20) { + [self addErrorWithCode:ECTRL description: [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]]; + return NO; + + } else { + NSLog(@"should not be able to get here"); + } + } while (*c); + + [self addErrorWithCode:EEOF description:@"Unexpected EOF while parsing string"]; + return NO; +} + +- (BOOL)scanUnicodeChar:(unichar *)x +{ + unichar hi, lo; + + if (![self scanHexQuad:&hi]) { + [self addErrorWithCode:EUNICODE description: @"Missing hex quad"]; + return NO; + } + + if (hi >= 0xd800) { // high surrogate char? + if (hi < 0xdc00) { // yes - expect a low char + + if (!(*c == '\\' && ++c && *c == 'u' && ++c && [self scanHexQuad:&lo])) { + [self addErrorWithCode:EUNICODE description: @"Missing low character in surrogate pair"]; + return NO; + } + + if (lo < 0xdc00 || lo >= 0xdfff) { + [self addErrorWithCode:EUNICODE description:@"Invalid low surrogate char"]; + return NO; + } + + hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000; + + } else if (hi < 0xe000) { + [self addErrorWithCode:EUNICODE description:@"Invalid high character in surrogate pair"]; + return NO; + } + } + + *x = hi; + return YES; +} + +- (BOOL)scanHexQuad:(unichar *)x +{ + *x = 0; + for (int i = 0; i < 4; i++) { + unichar uc = *c; + c++; + int d = (uc >= '0' && uc <= '9') + ? uc - '0' : (uc >= 'a' && uc <= 'f') + ? (uc - 'a' + 10) : (uc >= 'A' && uc <= 'F') + ? (uc - 'A' + 10) : -1; + if (d == -1) { + [self addErrorWithCode:EUNICODE description:@"Missing hex digit in quad"]; + return NO; + } + *x *= 16; + *x += d; + } + return YES; +} + +- (BOOL)scanNumber:(NSNumber **)o +{ + const char *ns = c; + + // The logic to test for validity of the number formatting is relicensed + // from JSON::XS with permission from its author Marc Lehmann. + // (Available at the CPAN: http://search.cpan.org/dist/JSON-XS/ .) + + if ('-' == *c) + c++; + + if ('0' == *c && c++) { + if (isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"Leading 0 disallowed in number"]; + return NO; + } + + } else if (!isdigit(*c) && c != ns) { + [self addErrorWithCode:EPARSENUM description: @"No digits after initial minus"]; + return NO; + + } else { + skipDigits(c); + } + + // Fractional part + if ('.' == *c && c++) { + + if (!isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"No digits after decimal point"]; + return NO; + } + skipDigits(c); + } + + // Exponential part + if ('e' == *c || 'E' == *c) { + c++; + + if ('-' == *c || '+' == *c) + c++; + + if (!isdigit(*c)) { + [self addErrorWithCode:EPARSENUM description: @"No digits after exponent"]; + return NO; + } + skipDigits(c); + } + + id str = [[NSString alloc] initWithBytesNoCopy:(char*)ns + length:c - ns + encoding:NSUTF8StringEncoding + freeWhenDone:NO]; + [str autorelease]; + if (str && (*o = [NSDecimalNumber decimalNumberWithString:str])) + return YES; + + [self addErrorWithCode:EPARSENUM description: @"Failed creating decimal instance"]; + return NO; +} + +- (BOOL)scanIsAtEnd +{ + skipWhitespace(c); + return !*c; +} + + +@end diff --git a/Classes/ThirdParty/DropboxSDK/JSON/SBJsonWriter.h b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonWriter.h new file mode 100644 index 0000000..f6f5e17 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonWriter.h @@ -0,0 +1,129 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import "SBJsonBase.h" + +/** + @brief Options for the writer class. + + This exists so the SBJSON facade can implement the options in the writer without having to re-declare them. + */ +@protocol SBJsonWriter + +/** + @brief Whether we are generating human-readable (multiline) JSON. + + Set whether or not to generate human-readable JSON. The default is NO, which produces + JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable + JSON with linebreaks after each array value and dictionary key/value pair, indented two + spaces per nesting level. + */ +@property BOOL humanReadable; + +/** + @brief Whether or not to sort the dictionary keys in the output. + + If this is set to YES, the dictionary keys in the JSON output will be in sorted order. + (This is useful if you need to compare two structures, for example.) The default is NO. + */ +@property BOOL sortKeys; + +/** + @brief Return JSON representation (or fragment) for the given object. + + Returns a string containing JSON representation of the passed in value, or nil on error. + If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. + + @param value any instance that can be represented as a JSON fragment + + */ +- (NSString*)stringWithObject:(id)value; + +@end + + +/** + @brief The JSON writer class. + + Objective-C types are mapped to JSON types in the following way: + + @li NSNull -> Null + @li NSString -> String + @li NSArray -> Array + @li NSDictionary -> Object + @li NSNumber (-initWithBool:) -> Boolean + @li NSNumber -> Number + + In JSON the keys of an object must be strings. NSDictionary keys need + not be, but attempting to convert an NSDictionary with non-string keys + into JSON will throw an exception. + + NSNumber instances created with the +initWithBool: method are + converted into the JSON boolean "true" and "false" values, and vice + versa. Any other NSNumber instances are converted to a JSON number the + way you would expect. + + */ +@interface SBJsonWriter : SBJsonBase { + +@private + BOOL sortKeys, humanReadable; +} + +@end + +// don't use - exists for backwards compatibility. Will be removed in 2.3. +@interface SBJsonWriter (Private) +- (NSString*)stringWithFragment:(id)value; +@end + +/** + @brief Allows generation of JSON for otherwise unsupported classes. + + If you have a custom class that you want to create a JSON representation for you can implement + this method in your class. It should return a representation of your object defined + in terms of objects that can be translated into JSON. For example, a Person + object might implement it like this: + + @code + - (id)jsonProxyObject { + return [NSDictionary dictionaryWithObjectsAndKeys: + name, @"name", + phone, @"phone", + email, @"email", + nil]; + } + @endcode + + */ +@interface NSObject (SBProxyForJson) +- (id)proxyForJson; +@end + diff --git a/Classes/ThirdParty/DropboxSDK/JSON/SBJsonWriter.m b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonWriter.m new file mode 100644 index 0000000..0f32904 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/JSON/SBJsonWriter.m @@ -0,0 +1,237 @@ +/* + Copyright (C) 2009 Stig Brautaset. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "SBJsonWriter.h" + +@interface SBJsonWriter () + +- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json; +- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json; +- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json; +- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json; + +- (NSString*)indent; + +@end + +@implementation SBJsonWriter + +static NSMutableCharacterSet *kEscapeChars; + ++ (void)initialize { + kEscapeChars = [[NSMutableCharacterSet characterSetWithRange: NSMakeRange(0,32)] retain]; + [kEscapeChars addCharactersInString: @"\"\\"]; +} + + +@synthesize sortKeys; +@synthesize humanReadable; + +/** + @deprecated This exists in order to provide fragment support in older APIs in one more version. + It should be removed in the next major version. + */ +- (NSString*)stringWithFragment:(id)value { + [self clearErrorTrace]; + depth = 0; + NSMutableString *json = [NSMutableString stringWithCapacity:128]; + + if ([self appendValue:value into:json]) + return json; + + return nil; +} + + +- (NSString*)stringWithObject:(id)value { + + if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) { + return [self stringWithFragment:value]; + } + + if ([value respondsToSelector:@selector(proxyForJson)]) { + NSString *tmp = [self stringWithObject:[value proxyForJson]]; + if (tmp) + return tmp; + } + + + [self clearErrorTrace]; + [self addErrorWithCode:EFRAGMENT description:@"Not valid type for JSON"]; + return nil; +} + + +- (NSString*)indent { + return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0]; +} + +- (BOOL)appendValue:(id)fragment into:(NSMutableString*)json { + if ([fragment isKindOfClass:[NSDictionary class]]) { + if (![self appendDictionary:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSArray class]]) { + if (![self appendArray:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSString class]]) { + if (![self appendString:fragment into:json]) + return NO; + + } else if ([fragment isKindOfClass:[NSNumber class]]) { + if ('c' == *[fragment objCType]) + [json appendString:[fragment boolValue] ? @"true" : @"false"]; + else + [json appendString:[fragment stringValue]]; + + } else if ([fragment isKindOfClass:[NSNull class]]) { + [json appendString:@"null"]; + } else if ([fragment respondsToSelector:@selector(proxyForJson)]) { + [self appendValue:[fragment proxyForJson] into:json]; + + } else { + [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]]; + return NO; + } + return YES; +} + +- (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + [json appendString:@"["]; + + BOOL addComma = NO; + for (id value in fragment) { + if (addComma) + [json appendString:@","]; + else + addComma = YES; + + if ([self humanReadable]) + [json appendString:[self indent]]; + + if (![self appendValue:value into:json]) { + return NO; + } + } + + depth--; + if ([self humanReadable] && [fragment count]) + [json appendString:[self indent]]; + [json appendString:@"]"]; + return YES; +} + +- (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json { + if (maxDepth && ++depth > maxDepth) { + [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; + return NO; + } + [json appendString:@"{"]; + + NSString *colon = [self humanReadable] ? @" : " : @":"; + BOOL addComma = NO; + NSArray *keys = [fragment allKeys]; + if (self.sortKeys) + keys = [keys sortedArrayUsingSelector:@selector(compare:)]; + + for (id value in keys) { + if (addComma) + [json appendString:@","]; + else + addComma = YES; + + if ([self humanReadable]) + [json appendString:[self indent]]; + + if (![value isKindOfClass:[NSString class]]) { + [self addErrorWithCode:EUNSUPPORTED description: @"JSON object key must be string"]; + return NO; + } + + if (![self appendString:value into:json]) + return NO; + + [json appendString:colon]; + if (![self appendValue:[fragment objectForKey:value] into:json]) { + [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"Unsupported value for key %@ in object", value]]; + return NO; + } + } + + depth--; + if ([self humanReadable] && [fragment count]) + [json appendString:[self indent]]; + [json appendString:@"}"]; + return YES; +} + +- (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json { + + [json appendString:@"\""]; + + NSRange esc = [fragment rangeOfCharacterFromSet:kEscapeChars]; + if ( !esc.length ) { + // No special chars -- can just add the raw string: + [json appendString:fragment]; + + } else { + NSUInteger length = [fragment length]; + for (NSUInteger i = 0; i < length; i++) { + unichar uc = [fragment characterAtIndex:i]; + switch (uc) { + case '"': [json appendString:@"\\\""]; break; + case '\\': [json appendString:@"\\\\"]; break; + case '\t': [json appendString:@"\\t"]; break; + case '\n': [json appendString:@"\\n"]; break; + case '\r': [json appendString:@"\\r"]; break; + case '\b': [json appendString:@"\\b"]; break; + case '\f': [json appendString:@"\\f"]; break; + default: + if (uc < 0x20) { + [json appendFormat:@"\\u%04x", uc]; + } else { + CFStringAppendCharacters((CFMutableStringRef)json, &uc, 1); + } + break; + + } + } + } + + [json appendString:@"\""]; + return YES; +} + + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/Crypto/Base64Transcoder.c b/Classes/ThirdParty/DropboxSDK/MPOAuth/Crypto/Base64Transcoder.c new file mode 100644 index 0000000..68d7774 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/Crypto/Base64Transcoder.c @@ -0,0 +1,230 @@ +/* + * Base64Transcoder.c + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Base64Transcoder.h" + +#include +#include + +const u_int8_t kBase64EncodeTable[64] = { + /* 0 */ 'A', /* 1 */ 'B', /* 2 */ 'C', /* 3 */ 'D', + /* 4 */ 'E', /* 5 */ 'F', /* 6 */ 'G', /* 7 */ 'H', + /* 8 */ 'I', /* 9 */ 'J', /* 10 */ 'K', /* 11 */ 'L', + /* 12 */ 'M', /* 13 */ 'N', /* 14 */ 'O', /* 15 */ 'P', + /* 16 */ 'Q', /* 17 */ 'R', /* 18 */ 'S', /* 19 */ 'T', + /* 20 */ 'U', /* 21 */ 'V', /* 22 */ 'W', /* 23 */ 'X', + /* 24 */ 'Y', /* 25 */ 'Z', /* 26 */ 'a', /* 27 */ 'b', + /* 28 */ 'c', /* 29 */ 'd', /* 30 */ 'e', /* 31 */ 'f', + /* 32 */ 'g', /* 33 */ 'h', /* 34 */ 'i', /* 35 */ 'j', + /* 36 */ 'k', /* 37 */ 'l', /* 38 */ 'm', /* 39 */ 'n', + /* 40 */ 'o', /* 41 */ 'p', /* 42 */ 'q', /* 43 */ 'r', + /* 44 */ 's', /* 45 */ 't', /* 46 */ 'u', /* 47 */ 'v', + /* 48 */ 'w', /* 49 */ 'x', /* 50 */ 'y', /* 51 */ 'z', + /* 52 */ '0', /* 53 */ '1', /* 54 */ '2', /* 55 */ '3', + /* 56 */ '4', /* 57 */ '5', /* 58 */ '6', /* 59 */ '7', + /* 60 */ '8', /* 61 */ '9', /* 62 */ '+', /* 63 */ '/' +}; + +/* +-1 = Base64 end of data marker. +-2 = White space (tabs, cr, lf, space) +-3 = Noise (all non whitespace, non-base64 characters) +-4 = Dangerous noise +-5 = Illegal noise (null byte) +*/ + +const int8_t kBase64DecodeTable[128] = { + /* 0x00 */ -5, /* 0x01 */ -3, /* 0x02 */ -3, /* 0x03 */ -3, + /* 0x04 */ -3, /* 0x05 */ -3, /* 0x06 */ -3, /* 0x07 */ -3, + /* 0x08 */ -3, /* 0x09 */ -2, /* 0x0a */ -2, /* 0x0b */ -2, + /* 0x0c */ -2, /* 0x0d */ -2, /* 0x0e */ -3, /* 0x0f */ -3, + /* 0x10 */ -3, /* 0x11 */ -3, /* 0x12 */ -3, /* 0x13 */ -3, + /* 0x14 */ -3, /* 0x15 */ -3, /* 0x16 */ -3, /* 0x17 */ -3, + /* 0x18 */ -3, /* 0x19 */ -3, /* 0x1a */ -3, /* 0x1b */ -3, + /* 0x1c */ -3, /* 0x1d */ -3, /* 0x1e */ -3, /* 0x1f */ -3, + /* ' ' */ -2, /* '!' */ -3, /* '"' */ -3, /* '#' */ -3, + /* '$' */ -3, /* '%' */ -3, /* '&' */ -3, /* ''' */ -3, + /* '(' */ -3, /* ')' */ -3, /* '*' */ -3, /* '+' */ 62, + /* ',' */ -3, /* '-' */ -3, /* '.' */ -3, /* '/' */ 63, + /* '0' */ 52, /* '1' */ 53, /* '2' */ 54, /* '3' */ 55, + /* '4' */ 56, /* '5' */ 57, /* '6' */ 58, /* '7' */ 59, + /* '8' */ 60, /* '9' */ 61, /* ':' */ -3, /* ';' */ -3, + /* '<' */ -3, /* '=' */ -1, /* '>' */ -3, /* '?' */ -3, + /* '@' */ -3, /* 'A' */ 0, /* 'B' */ 1, /* 'C' */ 2, + /* 'D' */ 3, /* 'E' */ 4, /* 'F' */ 5, /* 'G' */ 6, + /* 'H' */ 7, /* 'I' */ 8, /* 'J' */ 9, /* 'K' */ 10, + /* 'L' */ 11, /* 'M' */ 12, /* 'N' */ 13, /* 'O' */ 14, + /* 'P' */ 15, /* 'Q' */ 16, /* 'R' */ 17, /* 'S' */ 18, + /* 'T' */ 19, /* 'U' */ 20, /* 'V' */ 21, /* 'W' */ 22, + /* 'X' */ 23, /* 'Y' */ 24, /* 'Z' */ 25, /* '[' */ -3, + /* '\' */ -3, /* ']' */ -3, /* '^' */ -3, /* '_' */ -3, + /* '`' */ -3, /* 'a' */ 26, /* 'b' */ 27, /* 'c' */ 28, + /* 'd' */ 29, /* 'e' */ 30, /* 'f' */ 31, /* 'g' */ 32, + /* 'h' */ 33, /* 'i' */ 34, /* 'j' */ 35, /* 'k' */ 36, + /* 'l' */ 37, /* 'm' */ 38, /* 'n' */ 39, /* 'o' */ 40, + /* 'p' */ 41, /* 'q' */ 42, /* 'r' */ 43, /* 's' */ 44, + /* 't' */ 45, /* 'u' */ 46, /* 'v' */ 47, /* 'w' */ 48, + /* 'x' */ 49, /* 'y' */ 50, /* 'z' */ 51, /* '{' */ -3, + /* '|' */ -3, /* '}' */ -3, /* '~' */ -3, /* 0x7f */ -3 +}; + +const u_int8_t kBits_00000011 = 0x03; +const u_int8_t kBits_00001111 = 0x0F; +const u_int8_t kBits_00110000 = 0x30; +const u_int8_t kBits_00111100 = 0x3C; +const u_int8_t kBits_00111111 = 0x3F; +const u_int8_t kBits_11000000 = 0xC0; +const u_int8_t kBits_11110000 = 0xF0; +const u_int8_t kBits_11111100 = 0xFC; + +size_t EstimateBas64EncodedDataSize(size_t inDataSize) +{ +size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4; +theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72; +return(theEncodedDataSize); +} + +size_t EstimateBas64DecodedDataSize(size_t inDataSize) +{ +size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3; +//theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72; +return(theDecodedDataSize); +} + +bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize) +{ +size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize); +if (*ioOutputDataSize < theEncodedDataSize) + return(false); +*ioOutputDataSize = theEncodedDataSize; +const u_int8_t *theInPtr = (const u_int8_t *)inInputData; +u_int32_t theInIndex = 0, theOutIndex = 0; +for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0]; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +const size_t theRemainingBytes = inInputDataSize - theInIndex; +if (theRemainingBytes == 1) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = '='; + outOutputData[theOutIndex++] = '='; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex] = '\n'; + } + } +else if (theRemainingBytes == 2) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6]; + outOutputData[theOutIndex++] = '='; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex] = '\n'; + } + } +return(true); +} + +bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize) +{ +memset(ioOutputData, '.', *ioOutputDataSize); + +size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize); +if (*ioOutputDataSize < theDecodedDataSize) + return(false); +*ioOutputDataSize = 0; +const u_int8_t *theInPtr = (const u_int8_t *)inInputData; +u_int8_t *theOutPtr = (u_int8_t *)ioOutputData; +size_t theInIndex = 0, theOutIndex = 0; +u_int8_t theOutputOctet; +size_t theSequence = 0; +for (; theInIndex < inInputDataSize; ) + { + int8_t theSextet = 0; + + int8_t theCurrentInputOctet = theInPtr[theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + if (theSextet == -1) + break; + while (theSextet == -2) + { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + } + while (theSextet == -3) + { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + } + if (theSequence == 0) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100; + } + else if (theSequence == 1) + { + theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011; + theOutPtr[theOutIndex++] = theOutputOctet; + } + else if (theSequence == 2) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000; + } + else if (theSequence == 3) + { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111; + theOutPtr[theOutIndex++] = theOutputOctet; + } + else if (theSequence == 4) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000; + } + else if (theSequence == 5) + { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111; + theOutPtr[theOutIndex++] = theOutputOctet; + } + theSequence = (theSequence + 1) % 6; + if (theSequence != 2 && theSequence != 4) + theInIndex++; + } +*ioOutputDataSize = theOutIndex; +return(true); +} diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/Crypto/Base64Transcoder.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/Crypto/Base64Transcoder.h new file mode 100644 index 0000000..8752098 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/Crypto/Base64Transcoder.h @@ -0,0 +1,36 @@ +/* + * Base64Transcoder.h + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +extern size_t EstimateBas64EncodedDataSize(size_t inDataSize); +extern size_t EstimateBas64DecodedDataSize(size_t inDataSize); + +extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize); +extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize); + diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPDebug.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPDebug.h new file mode 100644 index 0000000..b59cd60 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPDebug.h @@ -0,0 +1,13 @@ +// +// MPDebug.h +// MPOAuthConnection +// +// Created by Karl Adam on 09.02.06. +// Copyright 2009 matrixPointer. All rights reserved. +// + +#ifdef DEBUG + #define MPLog(...) NSLog(__VA_ARGS__) +#else + #define MPLog(...) do { } while (0) +#endif diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuth.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuth.h new file mode 100644 index 0000000..062fced --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuth.h @@ -0,0 +1,20 @@ +// +// MPOAuth.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.13. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + + +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPI.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPI.h new file mode 100644 index 0000000..1449322 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPI.h @@ -0,0 +1,86 @@ +// +// MPOAuthAPI.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import +#import "MPOAuthCredentialStore.h" +#import "MPOAuthParameterFactory.h" + +extern NSString * const MPOAuthNotificationAccessTokenReceived; +extern NSString * const MPOAuthNotificationAccessTokenRejected; +extern NSString * const MPOAuthNotificationAccessTokenRefreshed; +extern NSString * const MPOAuthNotificationOAuthCredentialsReady; +extern NSString * const MPOAuthNotificationErrorHasOccurred; + +extern NSString * const MPOAuthCredentialRequestTokenKey; +extern NSString * const MPOAuthCredentialRequestTokenSecretKey; +extern NSString * const MPOAuthCredentialAccessTokenKey; +extern NSString * const MPOAuthCredentialAccessTokenSecretKey; +extern NSString * const MPOAuthCredentialSessionHandleKey; + +extern NSString * const MPOAuthTokenRefreshDateDefaultsKey; + +typedef enum { + MPOAuthSignatureSchemePlainText, + MPOAuthSignatureSchemeHMACSHA1, + MPOAuthSignatureSchemeRSASHA1 +} MPOAuthSignatureScheme; + +typedef enum { + MPOAuthAuthenticationStateUnauthenticated = 0, + MPOAuthAuthenticationStateAuthenticating = 1, + MPOAuthAuthenticationStateAuthenticated = 2 +} MPOAuthAuthenticationState; + +@protocol MPOAuthAPIInternalClient +@end + +@class MPOAuthAuthenticationMethod; + +@interface MPOAuthAPI : NSObject { +@private + id credentials_; + NSURL *baseURL_; + NSURL *authenticationURL_; + MPOAuthAuthenticationMethod *authenticationMethod_; + MPOAuthSignatureScheme signatureScheme_; + NSMutableArray *activeLoaders_; + MPOAuthAuthenticationState oauthAuthenticationState_; +} + +@property (nonatomic, readonly, retain) id credentials; +@property (nonatomic, readonly, retain) NSURL *baseURL; +@property (nonatomic, readonly, retain) NSURL *authenticationURL; +@property (nonatomic, readwrite, retain) MPOAuthAuthenticationMethod *authenticationMethod; +@property (nonatomic, readwrite, assign) MPOAuthSignatureScheme signatureScheme; + +@property (nonatomic, readonly, assign) MPOAuthAuthenticationState authenticationState; + + +- (id)initWithCredentials:(NSDictionary *)inCredentials andBaseURL:(NSURL *)inURL; +- (id)initWithCredentials:(NSDictionary *)inCredentials authenticationURL:(NSURL *)inAuthURL andBaseURL:(NSURL *)inBaseURL; +- (id)initWithCredentials:(NSDictionary *)inCredentials authenticationURL:(NSURL *)inAuthURL andBaseURL:(NSURL *)inBaseURL autoStart:(BOOL)aFlag; + +- (void)authenticate; +- (BOOL)isAuthenticated; + +- (void)performMethod:(NSString *)inMethod withTarget:(id)inTarget andAction:(SEL)inAction; +- (void)performMethod:(NSString *)inMethod atURL:(NSURL *)inURL withParameters:(NSArray *)inParameters withTarget:(id)inTarget andAction:(SEL)inAction; +- (void)performPOSTMethod:(NSString *)inMethod atURL:(NSURL *)inURL withParameters:(NSArray *)inParameters withTarget:(id)inTarget andAction:(SEL)inAction; +- (void)performURLRequest:(NSURLRequest *)inRequest withTarget:(id)inTarget andAction:(SEL)inAction; + +- (NSData *)dataForMethod:(NSString *)inMethod; +- (NSData *)dataForMethod:(NSString *)inMethod withParameters:(NSArray *)inParameters; +- (NSData *)dataForURL:(NSURL *)inURL andMethod:(NSString *)inMethod withParameters:(NSArray *)inParameters; + +- (id)credentialNamed:(NSString *)inCredentialName; +- (void)setCredential:(id)inCredential withName:(NSString *)inName; +- (void)removeCredentialNamed:(NSString *)inName; + +- (void)discardCredentials; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPI.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPI.m new file mode 100644 index 0000000..e87fc80 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPI.m @@ -0,0 +1,224 @@ +// +// MPOAuthAPI.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthAPIRequestLoader.h" +#import "MPOAuthAPI.h" +#import "MPOAuthCredentialConcreteStore.h" +#import "MPOAuthURLRequest.h" +#import "MPOAuthURLResponse.h" +#import "MPURLRequestParameter.h" +#import "MPOAuthAuthenticationMethod.h" + +#import "NSURL+MPURLParameterAdditions.h" + +NSString *kMPOAuthCredentialConsumerKey = @"kMPOAuthCredentialConsumerKey"; +NSString *kMPOAuthCredentialConsumerSecret = @"kMPOAuthCredentialConsumerSecret"; +NSString *kMPOAuthCredentialUsername = @"kMPOAuthCredentialUsername"; +NSString *kMPOAuthCredentialPassword = @"kMPOAuthCredentialPassword"; +NSString *kMPOAuthCredentialRequestToken = @"kMPOAuthCredentialRequestToken"; +NSString *kMPOAuthCredentialRequestTokenSecret = @"kMPOAuthCredentialRequestTokenSecret"; +NSString *kMPOAuthCredentialAccessToken = @"kMPOAuthCredentialAccessToken"; +NSString *kMPOAuthCredentialAccessTokenSecret = @"kMPOAuthCredentialAccessTokenSecret"; +NSString *kMPOAuthCredentialSessionHandle = @"kMPOAuthCredentialSessionHandle"; + +NSString *kMPOAuthSignatureMethod = @"kMPOAuthSignatureMethod"; +NSString * const MPOAuthTokenRefreshDateDefaultsKey = @"MPOAuthAutomaticTokenRefreshLastExpiryDate"; + +@interface MPOAuthAPI () +@property (nonatomic, readwrite, retain) id credentials; +@property (nonatomic, readwrite, retain) NSURL *authenticationURL; +@property (nonatomic, readwrite, retain) NSURL *baseURL; +@property (nonatomic, readwrite, retain) NSMutableArray *activeLoaders; +@property (nonatomic, readwrite, assign) MPOAuthAuthenticationState authenticationState; + +- (void)performMethod:(NSString *)inMethod atURL:(NSURL *)inURL withParameters:(NSArray *)inParameters withTarget:(id)inTarget andAction:(SEL)inAction usingHTTPMethod:(NSString *)inHTTPMethod; +@end + +@implementation MPOAuthAPI + +- (id)initWithCredentials:(NSDictionary *)inCredentials andBaseURL:(NSURL *)inBaseURL { + return [self initWithCredentials:inCredentials authenticationURL:inBaseURL andBaseURL:inBaseURL]; +} + +- (id)initWithCredentials:(NSDictionary *)inCredentials authenticationURL:(NSURL *)inAuthURL andBaseURL:(NSURL *)inBaseURL { + return [self initWithCredentials:inCredentials authenticationURL:inBaseURL andBaseURL:inBaseURL autoStart:YES]; +} + +- (id)initWithCredentials:(NSDictionary *)inCredentials authenticationURL:(NSURL *)inAuthURL andBaseURL:(NSURL *)inBaseURL autoStart:(BOOL)aFlag { + if (self = [super init]) { + self.authenticationURL = inAuthURL; + self.baseURL = inBaseURL; + self.authenticationState = MPOAuthAuthenticationStateUnauthenticated; + credentials_ = [[MPOAuthCredentialConcreteStore alloc] initWithCredentials:inCredentials forBaseURL:inBaseURL withAuthenticationURL:inAuthURL]; + self.authenticationMethod = [[MPOAuthAuthenticationMethod alloc] initWithAPI:self forURL:inAuthURL]; + self.signatureScheme = MPOAuthSignatureSchemeHMACSHA1; + + activeLoaders_ = [[NSMutableArray alloc] initWithCapacity:10]; + + if (aFlag) { + [self authenticate]; + } + } + return self; +} + +- (oneway void)dealloc { + self.credentials = nil; + self.baseURL = nil; + self.authenticationURL = nil; + self.authenticationMethod = nil; + self.activeLoaders = nil; + + [super dealloc]; +} + +@synthesize credentials = credentials_; +@synthesize baseURL = baseURL_; +@synthesize authenticationURL = authenticationURL_; +@synthesize authenticationMethod = authenticationMethod_; +@synthesize signatureScheme = signatureScheme_; +@synthesize activeLoaders = activeLoaders_; +@synthesize authenticationState = oauthAuthenticationState_; + +#pragma mark - + +- (void)setSignatureScheme:(MPOAuthSignatureScheme)inScheme { + signatureScheme_ = inScheme; + + NSString *methodString = @"HMAC-SHA1"; + + switch (signatureScheme_) { + case MPOAuthSignatureSchemePlainText: + methodString = @"PLAINTEXT"; + break; + case MPOAuthSignatureSchemeRSASHA1: + methodString = @"RSA-SHA1"; + case MPOAuthSignatureSchemeHMACSHA1: + default: + // already initted to the default + break; + } + + [(MPOAuthCredentialConcreteStore *)credentials_ setSignatureMethod:methodString]; +} + +#pragma mark - + +- (void)authenticate { + NSAssert(credentials_.consumerKey, @"A Consumer Key is required for use of OAuth."); + [self.authenticationMethod authenticate]; +} + +- (BOOL)isAuthenticated { + return (self.authenticationState == MPOAuthAuthenticationStateAuthenticated); +} + +#pragma mark - + +- (void)performMethod:(NSString *)inMethod withTarget:(id)inTarget andAction:(SEL)inAction { + [self performMethod:inMethod atURL:self.baseURL withParameters:nil withTarget:inTarget andAction:inAction usingHTTPMethod:@"GET"]; +} + +- (void)performMethod:(NSString *)inMethod atURL:(NSURL *)inURL withParameters:(NSArray *)inParameters withTarget:(id)inTarget andAction:(SEL)inAction { + [self performMethod:inMethod atURL:inURL withParameters:inParameters withTarget:inTarget andAction:inAction usingHTTPMethod:@"GET"]; +} + +- (void)performPOSTMethod:(NSString *)inMethod atURL:(NSURL *)inURL withParameters:(NSArray *)inParameters withTarget:(id)inTarget andAction:(SEL)inAction { + [self performMethod:inMethod atURL:inURL withParameters:inParameters withTarget:inTarget andAction:inAction usingHTTPMethod:@"POST"]; +} + +- (void)performMethod:(NSString *)inMethod atURL:(NSURL *)inURL withParameters:(NSArray *)inParameters withTarget:(id)inTarget andAction:(SEL)inAction usingHTTPMethod:(NSString *)inHTTPMethod { + if (!inMethod && ![inURL path] && ![inURL query]) { + [NSException raise:@"MPOAuthNilMethodRequestException" format:@"Nil was passed as the method to be performed on %@", inURL]; + } + + NSURL *requestURL = inMethod ? [NSURL URLWithString:inMethod relativeToURL:inURL] : inURL; + MPOAuthURLRequest *aRequest = [[MPOAuthURLRequest alloc] initWithURL:requestURL andParameters:inParameters]; + MPOAuthAPIRequestLoader *loader = [[MPOAuthAPIRequestLoader alloc] initWithRequest:aRequest]; + + aRequest.HTTPMethod = inHTTPMethod; + loader.credentials = self.credentials; + loader.target = inTarget; + loader.action = inAction ? inAction : @selector(_performedLoad:receivingData:); + + [loader loadSynchronously:NO]; + // [self.activeLoaders addObject:loader]; + + [loader release]; + [aRequest release]; +} + +- (void)performURLRequest:(NSURLRequest *)inRequest withTarget:(id)inTarget andAction:(SEL)inAction { + if (!inRequest && ![[inRequest URL] path] && ![[inRequest URL] query]) { + [NSException raise:@"MPOAuthNilMethodRequestException" format:@"Nil was passed as the method to be performed on %@", inRequest]; + } + + MPOAuthURLRequest *aRequest = [[MPOAuthURLRequest alloc] initWithURLRequest:inRequest]; + MPOAuthAPIRequestLoader *loader = [[MPOAuthAPIRequestLoader alloc] initWithRequest:aRequest]; + + loader.credentials = self.credentials; + loader.target = inTarget; + loader.action = inAction ? inAction : @selector(_performedLoad:receivingData:); + + [loader loadSynchronously:NO]; + // [self.activeLoaders addObject:loader]; + + [loader release]; + [aRequest release]; +} + +- (NSData *)dataForMethod:(NSString *)inMethod { + return [self dataForURL:self.baseURL andMethod:inMethod withParameters:nil]; +} + +- (NSData *)dataForMethod:(NSString *)inMethod withParameters:(NSArray *)inParameters { + return [self dataForURL:self.baseURL andMethod:inMethod withParameters:inParameters]; +} + +- (NSData *)dataForURL:(NSURL *)inURL andMethod:(NSString *)inMethod withParameters:(NSArray *)inParameters { + NSURL *requestURL = [NSURL URLWithString:inMethod relativeToURL:inURL]; + MPOAuthURLRequest *aRequest = [[MPOAuthURLRequest alloc] initWithURL:requestURL andParameters:inParameters]; + MPOAuthAPIRequestLoader *loader = [[MPOAuthAPIRequestLoader alloc] initWithRequest:aRequest]; + + loader.credentials = self.credentials; + [loader loadSynchronously:YES]; + + [loader autorelease]; + [aRequest release]; + + return loader.data; +} + +#pragma mark - + +- (id)credentialNamed:(NSString *)inCredentialName { + return [self.credentials credentialNamed:inCredentialName]; +} + +- (void)setCredential:(id)inCredential withName:(NSString *)inName { + [(MPOAuthCredentialConcreteStore *)self.credentials setCredential:inCredential withName:inName]; +} + +- (void)removeCredentialNamed:(NSString *)inName { + [(MPOAuthCredentialConcreteStore *)self.credentials removeCredentialNamed:inName]; +} + +- (void)discardCredentials { + [self.credentials discardOAuthCredentials]; + + self.authenticationState = MPOAuthAuthenticationStateUnauthenticated; +} + +#pragma mark - +#pragma mark - Private APIs - + +- (void)_performedLoad:(MPOAuthAPIRequestLoader *)inLoader receivingData:(NSData *)inData { +// NSLog(@"loaded %@, and got %@", inLoader, inData); +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPIRequestLoader.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPIRequestLoader.h new file mode 100644 index 0000000..affe1a2 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPIRequestLoader.h @@ -0,0 +1,50 @@ +// +// MPOAuthAPIRequestLoader.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + +extern NSString * const MPOAuthNotificationRequestTokenReceived; +extern NSString * const MPOAuthNotificationRequestTokenRejected; +extern NSString * const MPOAuthNotificationAccessTokenReceived; +extern NSString * const MPOAuthNotificationAccessTokenRejected; +extern NSString * const MPOAuthNotificationAccessTokenRefreshed; +extern NSString * const MPOAuthNotificationErrorHasOccurred; + +@protocol MPOAuthCredentialStore; +@protocol MPOAuthParameterFactory; + +@class MPOAuthURLRequest; +@class MPOAuthURLResponse; +@class MPOAuthCredentialConcreteStore; + +@interface MPOAuthAPIRequestLoader : NSObject { + MPOAuthCredentialConcreteStore *_credentials; + MPOAuthURLRequest *_oauthRequest; + MPOAuthURLResponse *_oauthResponse; + NSMutableData *_dataBuffer; + NSString *_dataAsString; + NSError *_error; + id _target; + SEL _action; +} + +@property (nonatomic, readwrite, retain) id credentials; +@property (nonatomic, readwrite, retain) MPOAuthURLRequest *oauthRequest; +@property (nonatomic, readwrite, retain) MPOAuthURLResponse *oauthResponse; +@property (nonatomic, readonly, retain) NSData *data; +@property (nonatomic, readonly, retain) NSString *responseString; +@property (nonatomic, readwrite, assign) id target; +@property (nonatomic, readwrite, assign) SEL action; + +- (id)initWithURL:(NSURL *)inURL; +- (id)initWithRequest:(MPOAuthURLRequest *)inRequest; + +- (void)loadSynchronously:(BOOL)inSynchronous; + +@end + diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPIRequestLoader.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPIRequestLoader.m new file mode 100644 index 0000000..e72f6df --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAPIRequestLoader.m @@ -0,0 +1,220 @@ +// +// MPOAuthAPIRequestLoader.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthAPIRequestLoader.h" +#import "MPOAuthURLRequest.h" +#import "MPOAuthURLResponse.h" +#import "MPOAuthConnection.h" +#import "MPOAuthCredentialStore.h" +#import "MPOAuthCredentialConcreteStore.h" +#import "MPURLRequestParameter.h" +#import "NSURLResponse+Encoding.h" +#import "MPDebug.h" + +NSString * const MPOAuthNotificationRequestTokenReceived = @"MPOAuthNotificationRequestTokenReceived"; +NSString * const MPOAuthNotificationRequestTokenRejected = @"MPOAuthNotificationRequestTokenRejected"; +NSString * const MPOAuthNotificationAccessTokenReceived = @"MPOAuthNotificationAccessTokenReceived"; +NSString * const MPOAuthNotificationAccessTokenRejected = @"MPOAuthNotificationAccessTokenRejected"; +NSString * const MPOAuthNotificationAccessTokenRefreshed = @"MPOAuthNotificationAccessTokenRefreshed"; +NSString * const MPOAuthNotificationOAuthCredentialsReady = @"MPOAuthNotificationOAuthCredentialsReady"; +NSString * const MPOAuthNotificationErrorHasOccurred = @"MPOAuthNotificationErrorHasOccurred"; + +@interface MPOAuthURLResponse () +@property (nonatomic, readwrite, retain) NSURLResponse *urlResponse; +@property (nonatomic, readwrite, retain) NSDictionary *oauthParameters; +@end + + +@interface MPOAuthAPIRequestLoader () +@property (nonatomic, readwrite, retain) NSData *data; +@property (nonatomic, readwrite, retain) NSString *responseString; + +- (void)_interrogateResponseForOAuthData; +@end + +@protocol MPOAuthAPIInternalClient; + +@implementation MPOAuthAPIRequestLoader + +- (id)initWithURL:(NSURL *)inURL { + return [self initWithRequest:[[[MPOAuthURLRequest alloc] initWithURL:inURL andParameters:nil] autorelease]]; +} + +- (id)initWithRequest:(MPOAuthURLRequest *)inRequest { + if (self = [super init]) { + self.oauthRequest = inRequest; + _dataBuffer = [[NSMutableData alloc] init]; + } + return self; +} + +- (oneway void)dealloc { + self.credentials = nil; + self.oauthRequest = nil; + self.oauthResponse = nil; + self.data = nil; + self.responseString = nil; + + [super dealloc]; +} + +@synthesize credentials = _credentials; +@synthesize oauthRequest = _oauthRequest; +@synthesize oauthResponse = _oauthResponse; +@synthesize data = _dataBuffer; +@synthesize responseString = _dataAsString; +@synthesize target = _target; +@synthesize action = _action; + +#pragma mark - + +- (MPOAuthURLResponse *)oauthResponse { + if (!_oauthResponse) { + _oauthResponse = [[MPOAuthURLResponse alloc] init]; + } + + return _oauthResponse; +} + +- (NSString *)responseString { + if (!_dataAsString) { + _dataAsString = [[NSString alloc] initWithData:self.data encoding:[self.oauthResponse.urlResponse encoding]]; + } + + return _dataAsString; +} + +- (void)loadSynchronously:(BOOL)inSynchronous { + NSAssert(_credentials, @"Unable to load without valid credentials"); + NSAssert(_credentials.consumerKey, @"Unable to load, credentials contain no consumer key"); + + if (!inSynchronous) { + [MPOAuthConnection connectionWithRequest:self.oauthRequest delegate:self credentials:self.credentials]; + } else { + MPOAuthURLResponse *theOAuthResponse = nil; + self.data = [MPOAuthConnection sendSynchronousRequest:self.oauthRequest usingCredentials:self.credentials returningResponse:&theOAuthResponse error:nil]; + self.oauthResponse = theOAuthResponse; + [self _interrogateResponseForOAuthData]; + } +} + +#pragma mark - + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + MPLog(@"%p: [%@ %@] %@, %@", self, NSStringFromClass([self class]), NSStringFromSelector(_cmd), connection, error); + if ([_target respondsToSelector:@selector(loader:didFailWithError:)]) { + [_target performSelector: @selector(loader:didFailWithError:) withObject: self withObject: error]; + } +} + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + self.oauthResponse.urlResponse = response; +} + +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { + MPLog(@"%@", NSStringFromSelector(_cmd)); +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + [_dataBuffer appendData:data]; +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse { + MPLog( @"[%@ %@]: %@, %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), request, redirectResponse); + return request; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + [self _interrogateResponseForOAuthData]; + + if (_action) { + if ([_target conformsToProtocol:@protocol(MPOAuthAPIInternalClient)]) { + [_target performSelector:_action withObject:self withObject:self.data]; + } else { + [_target performSelector:_action withObject:self.oauthRequest.url withObject:self.responseString]; + } + } +} + +#pragma mark - + +- (void)_interrogateResponseForOAuthData { + NSString *response = self.responseString; + NSDictionary *foundParameters = nil; + NSInteger status = [(NSHTTPURLResponse *)[self.oauthResponse urlResponse] statusCode]; + + if ([response length] > 5 && [[response substringToIndex:5] isEqualToString:@"oauth"]) { + foundParameters = [MPURLRequestParameter parameterDictionaryFromString:response]; + self.oauthResponse.oauthParameters = foundParameters; + + if (status == 401 || ([response length] > 13 && [[response substringToIndex:13] isEqualToString:@"oauth_problem"])) { + NSString *aParameterValue = nil; + MPLog(@"oauthProblem = %@", foundParameters); + + if ([foundParameters count] && (aParameterValue = [foundParameters objectForKey:@"oauth_problem"])) { + if ([aParameterValue isEqualToString:@"token_rejected"]) { + if (self.credentials.requestToken && !self.credentials.accessToken) { + [_credentials setRequestToken:nil]; + [_credentials setRequestTokenSecret:nil]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MPOAuthNotificationRequestTokenRejected + object:nil + userInfo:foundParameters]; + } else if (self.credentials.accessToken && !self.credentials.requestToken) { + // your access token may be invalid due to a number of reasons so it's up to the + // user to decide whether or not to remove them + [[NSNotificationCenter defaultCenter] postNotificationName:MPOAuthNotificationAccessTokenRejected + object:nil + userInfo:foundParameters]; + + } + } + + // something's messed up, so throw an error + [[NSNotificationCenter defaultCenter] postNotificationName:MPOAuthNotificationErrorHasOccurred + object:nil + userInfo:foundParameters]; + } + } else if ([response length] > 11 && [[response substringToIndex:11] isEqualToString:@"oauth_token"]) { + NSString *aParameterValue = nil; + MPLog(@"foundParameters = %@", foundParameters); + + if ([foundParameters count] && (aParameterValue = [foundParameters objectForKey:@"oauth_token"])) { + if (!self.credentials.requestToken && !self.credentials.accessToken) { + [_credentials setRequestToken:aParameterValue]; + [_credentials setRequestTokenSecret:[foundParameters objectForKey:@"oauth_token_secret"]]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MPOAuthNotificationRequestTokenReceived + object:nil + userInfo:foundParameters]; + + } else if (!self.credentials.accessToken && self.credentials.requestToken) { + [_credentials setRequestToken:nil]; + [_credentials setRequestTokenSecret:nil]; + [_credentials setAccessToken:aParameterValue]; + [_credentials setAccessTokenSecret:[foundParameters objectForKey:@"oauth_token_secret"]]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MPOAuthNotificationAccessTokenReceived + object:nil + userInfo:foundParameters]; + + } else if (self.credentials.accessToken && !self.credentials.requestToken) { + // replace the current token + [_credentials setAccessToken:aParameterValue]; + [_credentials setAccessTokenSecret:[foundParameters objectForKey:@"oauth_token_secret"]]; + + [[NSNotificationCenter defaultCenter] postNotificationName:MPOAuthNotificationAccessTokenRefreshed + object:nil + userInfo:foundParameters]; + } + } + } + } +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethod.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethod.h new file mode 100644 index 0000000..f3dbd39 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethod.h @@ -0,0 +1,30 @@ +// +// MPOAuthAuthenticationMethod.h +// MPOAuthConnection +// +// Created by Karl Adam on 09.12.19. +// Copyright 2009 matrixPointer. All rights reserved. +// + +#import + +extern NSString * const MPOAuthAccessTokenURLKey; + +@class MPOAuthAPI; + +@interface MPOAuthAuthenticationMethod : NSObject { + MPOAuthAPI *oauthAPI_; + NSURL *oauthGetAccessTokenURL_; + NSTimer *refreshTimer_; +} + +@property (nonatomic, readwrite, assign) MPOAuthAPI *oauthAPI; +@property (nonatomic, readwrite, retain) NSURL *oauthGetAccessTokenURL; + +- (id)initWithAPI:(MPOAuthAPI *)inAPI forURL:(NSURL *)inURL; +- (id)initWithAPI:(MPOAuthAPI *)inAPI forURL:(NSURL *)inURL withConfiguration:(NSDictionary *)inConfig; +- (void)authenticate; + +- (void)setTokenRefreshInterval:(NSTimeInterval)inTimeInterval; +- (void)refreshAccessToken; +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethod.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethod.m new file mode 100644 index 0000000..70d6749 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethod.m @@ -0,0 +1,131 @@ +// +// MPOAuthAuthenticationMethod.m +// MPOAuthConnection +// +// Created by Karl Adam on 09.12.19. +// Copyright 2009 matrixPointer. All rights reserved. +// + +#import "MPOAuthAuthenticationMethod.h" +#import "MPOAuthAuthenticationMethodOAuth.h" +#import "MPOAuthCredentialConcreteStore.h" +#import "MPURLRequestParameter.h" + +#import "NSURL+MPURLParameterAdditions.h" + +NSString * const MPOAuthAccessTokenURLKey = @"MPOAuthAccessTokenURL"; + +@interface MPOAuthAuthenticationMethod () +@property (nonatomic, readwrite, retain) NSTimer *refreshTimer; + ++ (Class)_authorizationMethodClassForURL:(NSURL *)inBaseURL withConfiguration:(NSDictionary **)outConfig; +- (id)initWithAPI:(MPOAuthAPI *)inAPI forURL:(NSURL *)inURL withConfiguration:(NSDictionary *)inConfig; +- (void)_automaticallyRefreshAccessToken:(NSTimer *)inTimer; +@end + +@implementation MPOAuthAuthenticationMethod +- (id)initWithAPI:(MPOAuthAPI *)inAPI forURL:(NSURL *)inURL { + return [self initWithAPI:inAPI forURL:inURL withConfiguration:nil]; +} + +- (id)initWithAPI:(MPOAuthAPI *)inAPI forURL:(NSURL *)inURL withConfiguration:(NSDictionary *)inConfig { + if ([[self class] isEqual:[MPOAuthAuthenticationMethod class]]) { + NSDictionary *configuration = nil; + Class methodClass = [[self class] _authorizationMethodClassForURL:inURL withConfiguration:&configuration]; + [self release]; + + self = [[methodClass alloc] initWithAPI:inAPI forURL:inURL withConfiguration:configuration]; + } else if (self = [super init]) { + self.oauthAPI = inAPI; + } + + return self; +} + +- (oneway void)dealloc { + self.oauthAPI = nil; + self.oauthGetAccessTokenURL = nil; + + [self.refreshTimer invalidate]; + self.refreshTimer = nil; + + [super dealloc]; +} + +@synthesize oauthAPI = oauthAPI_; +@synthesize oauthGetAccessTokenURL = oauthGetAccessTokenURL_; +@synthesize refreshTimer = refreshTimer_; + +#pragma mark - + ++ (Class)_authorizationMethodClassForURL:(NSURL *)inBaseURL withConfiguration:(NSDictionary **)outConfig { + Class methodClass = [MPOAuthAuthenticationMethodOAuth class]; + NSString *oauthConfigPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"oauthAutoConfig" ofType:@"plist"]; + NSDictionary *oauthConfigDictionary = [NSDictionary dictionaryWithContentsOfFile:oauthConfigPath]; + + for ( NSString *domainString in [oauthConfigDictionary keyEnumerator]) { + if ([inBaseURL domainMatches:domainString]) { + NSDictionary *oauthConfig = [oauthConfigDictionary objectForKey:domainString]; + + NSArray *requestedMethods = [oauthConfig objectForKey:@"MPOAuthAuthenticationPreferredMethods"]; + NSString *requestedMethod = nil; + for (requestedMethod in requestedMethods) { + Class requestedMethodClass = NSClassFromString(requestedMethod); + + if (requestedMethodClass) { + methodClass = requestedMethodClass; + } + break; + } + + if (requestedMethod) { + *outConfig = [oauthConfig objectForKey:requestedMethod]; + } else { + *outConfig = oauthConfig; + } + + break; + } + } + + return methodClass; +} + +#pragma mark - + +- (void)authenticate { + [NSException raise:@"Not Implemented" format:@"All subclasses of MPOAuthAuthenticationMethod are required to implement -authenticate"]; +} + +- (void)setTokenRefreshInterval:(NSTimeInterval)inTimeInterval { + if (!self.refreshTimer && inTimeInterval > 0.0) { + self.refreshTimer = [NSTimer scheduledTimerWithTimeInterval:inTimeInterval target:self selector:@selector(_automaticallyRefreshAccessToken:) userInfo:nil repeats:YES]; + } +} + +- (void)refreshAccessToken { + MPURLRequestParameter *sessionHandleParameter = nil; + MPOAuthCredentialConcreteStore *credentials = (MPOAuthCredentialConcreteStore *)[self.oauthAPI credentials]; + + if (credentials.sessionHandle) { + sessionHandleParameter = [[MPURLRequestParameter alloc] init]; + sessionHandleParameter.name = @"oauth_session_handle"; + sessionHandleParameter.value = credentials.sessionHandle; + } + + [self.oauthAPI performMethod:nil + atURL:self.oauthGetAccessTokenURL + withParameters:sessionHandleParameter ? [NSArray arrayWithObject:sessionHandleParameter] : nil + withTarget:nil + andAction:nil]; + + [sessionHandleParameter release]; +} + +#pragma mark - + +- (void)_automaticallyRefreshAccessToken:(NSTimer *)inTimer { + [self refreshAccessToken]; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethodOAuth.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethodOAuth.h new file mode 100644 index 0000000..93f94a2 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethodOAuth.h @@ -0,0 +1,44 @@ +// +// MPOAuthAuthenticationMethodOAuth.h +// MPOAuthConnection +// +// Created by Karl Adam on 09.12.19. +// Copyright 2009 matrixPointer. All rights reserved. +// + +#import +#import "MPOAuthAuthenticationMethod.h" +#import "MPOAuthAPI.h" +#import "MPOAuthAPIRequestLoader.h" + +extern NSString * const MPOAuthNotificationRequestTokenReceived; +extern NSString * const MPOAuthNotificationRequestTokenRejected; + +@protocol MPOAuthAuthenticationMethodOAuthDelegate; + +@interface MPOAuthAuthenticationMethodOAuth : MPOAuthAuthenticationMethod { + NSURL *oauthRequestTokenURL_; + NSURL *oauthAuthorizeTokenURL_; + BOOL oauth10aModeActive_; + + id delegate_; +} + +@property (nonatomic, readwrite, assign) id delegate; + +@property (nonatomic, readwrite, retain) NSURL *oauthRequestTokenURL; +@property (nonatomic, readwrite, retain) NSURL *oauthAuthorizeTokenURL; + +- (void)authenticate; + +@end + +@protocol MPOAuthAuthenticationMethodOAuthDelegate +- (NSURL *)callbackURLForCompletedUserAuthorization; +- (BOOL)automaticallyRequestAuthenticationFromURL:(NSURL *)inAuthURL withCallbackURL:(NSURL *)inCallbackURL; + +@optional +- (NSString *)oauthVerifierForCompletedUserAuthorization; +- (void)authenticationDidFailWithError:(NSError *)error; +@end + diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethodOAuth.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethodOAuth.m new file mode 100644 index 0000000..7658b91 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthAuthenticationMethodOAuth.m @@ -0,0 +1,217 @@ +// +// MPOAuthAuthenticationMethodOAuth.m +// MPOAuthConnection +// +// Created by Karl Adam on 09.12.19. +// Copyright 2009 matrixPointer. All rights reserved. +// + +#import "MPOAuthAuthenticationMethodOAuth.h" +#import "MPOAuthAPI.h" +#import "MPOAuthAPIRequestLoader.h" +#import "MPOAuthURLResponse.h" +#import "MPOAuthCredentialStore.h" +#import "MPOAuthCredentialConcreteStore.h" +#import "MPDebug.h" +#import "MPURLRequestParameter.h" + +#import "NSURL+MPURLParameterAdditions.h" + +NSString *MPOAuthRequestTokenURLKey = @"MPOAuthRequestTokenURL"; +NSString *MPOAuthUserAuthorizationURLKey = @"MPOAuthUserAuthorizationURL"; +NSString *MPOAuthUserAuthorizationMobileURLKey = @"MPOAuthUserAuthorizationMobileURL"; + +NSString * const MPOAuthCredentialRequestTokenKey = @"oauth_token_request"; +NSString * const MPOAuthCredentialRequestTokenSecretKey = @"oauth_token_request_secret"; +NSString * const MPOAuthCredentialAccessTokenKey = @"oauth_token_access"; +NSString * const MPOAuthCredentialAccessTokenSecretKey = @"oauth_token_access_secret"; +NSString * const MPOAuthCredentialSessionHandleKey = @"oauth_session_handle"; +NSString * const MPOAuthCredentialVerifierKey = @"oauth_verifier"; + +@interface MPOAuthAPI () +@property (nonatomic, readwrite, assign) MPOAuthAuthenticationState authenticationState; +@end + + +@interface MPOAuthAuthenticationMethodOAuth () +@property (nonatomic, readwrite, assign) BOOL oauth10aModeActive; + +- (void)_authenticationRequestForRequestToken; +- (void)_authenticationRequestForUserPermissionsConfirmationAtURL:(NSURL *)inURL; +- (void)_authenticationRequestForAccessToken; + +@end + +@implementation MPOAuthAuthenticationMethodOAuth + +- (id)initWithAPI:(MPOAuthAPI *)inAPI forURL:(NSURL *)inURL withConfiguration:(NSDictionary *)inConfig { + if (self = [super initWithAPI:inAPI forURL:inURL withConfiguration:inConfig]) { + + NSAssert( [inConfig count] >= 3, @"Incorrect number of oauth authorization methods"); + self.oauthRequestTokenURL = [NSURL URLWithString:[inConfig objectForKey:MPOAuthRequestTokenURLKey]]; + self.oauthAuthorizeTokenURL = [NSURL URLWithString:[inConfig objectForKey:MPOAuthUserAuthorizationURLKey]]; + self.oauthGetAccessTokenURL = [NSURL URLWithString:[inConfig objectForKey:MPOAuthAccessTokenURLKey]]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_requestTokenReceived:) name:MPOAuthNotificationRequestTokenReceived object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_requestTokenRejected:) name:MPOAuthNotificationRequestTokenRejected object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_accessTokenReceived:) name:MPOAuthNotificationAccessTokenReceived object:nil]; + } + return self; +} + +- (oneway void)dealloc { + self.oauthRequestTokenURL = nil; + self.oauthAuthorizeTokenURL = nil; + + [super dealloc]; +} + +@synthesize delegate = delegate_; +@synthesize oauthRequestTokenURL = oauthRequestTokenURL_; +@synthesize oauthAuthorizeTokenURL = oauthAuthorizeTokenURL_; +@synthesize oauth10aModeActive = oauth10aModeActive_; + +#pragma mark - + +- (void)authenticate { + id credentials = [self.oauthAPI credentials]; + + if (!credentials.accessToken && !credentials.requestToken) { + [self _authenticationRequestForRequestToken]; + } else if (!credentials.accessToken) { + [self _authenticationRequestForAccessToken]; + } else if (credentials.accessToken && [[NSUserDefaults standardUserDefaults] objectForKey:MPOAuthTokenRefreshDateDefaultsKey]) { + NSTimeInterval expiryDateInterval = [[NSUserDefaults standardUserDefaults] doubleForKey:MPOAuthTokenRefreshDateDefaultsKey]; + NSDate *tokenExpiryDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expiryDateInterval]; + + if ([tokenExpiryDate compare:[NSDate date]] == NSOrderedAscending) { + [self refreshAccessToken]; + } + } +} + +- (void)_authenticationRequestForRequestToken { + if (self.oauthRequestTokenURL) { + MPLog(@"--> Performing Request Token Request: %@", self.oauthRequestTokenURL); + + // Append the oauth_callbackUrl parameter for requesting the request token + MPURLRequestParameter *callbackParameter = nil; + if (self.delegate && [self.delegate respondsToSelector: @selector(callbackURLForCompletedUserAuthorization)]) { + NSURL *callbackURL = [self.delegate callbackURLForCompletedUserAuthorization]; + callbackParameter = [[[MPURLRequestParameter alloc] initWithName:@"oauth_callback" andValue:[callbackURL absoluteString]] autorelease]; + } else { + // oob = "Out of bounds" + callbackParameter = [[[MPURLRequestParameter alloc] initWithName:@"oauth_callback" andValue:@"oob"] autorelease]; + } + + NSArray *params = [NSArray arrayWithObject:callbackParameter]; + [self.oauthAPI performMethod:nil atURL:self.oauthRequestTokenURL withParameters:params withTarget:self andAction:@selector(_authenticationRequestForRequestTokenSuccessfulLoad:withData:)]; + } +} + +- (void)_authenticationRequestForRequestTokenSuccessfulLoad:(MPOAuthAPIRequestLoader *)inLoader withData:(NSData *)inData { + NSDictionary *oauthResponseParameters = inLoader.oauthResponse.oauthParameters; + NSString *xoauthRequestAuthURL = [oauthResponseParameters objectForKey:@"xoauth_request_auth_url"]; // a common custom extension, used by Yahoo! + NSURL *userAuthURL = xoauthRequestAuthURL ? [NSURL URLWithString:xoauthRequestAuthURL] : self.oauthAuthorizeTokenURL; + NSURL *callbackURL = nil; + + if (!self.oauth10aModeActive) { + callbackURL = [self.delegate respondsToSelector:@selector(callbackURLForCompletedUserAuthorization)] ? [self.delegate callbackURLForCompletedUserAuthorization] : nil; + } + + NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys: [oauthResponseParameters objectForKey: @"oauth_token"], @"oauth_token", + callbackURL, @"oauth_callback", + nil]; + + userAuthURL = [userAuthURL urlByAddingParameterDictionary:parameters]; + BOOL delegateWantsToBeInvolved = [self.delegate respondsToSelector:@selector(automaticallyRequestAuthenticationFromURL:withCallbackURL:)]; + + if (!delegateWantsToBeInvolved || (delegateWantsToBeInvolved && [self.delegate automaticallyRequestAuthenticationFromURL:userAuthURL withCallbackURL:callbackURL])) { + MPLog(@"--> Automatically Performing User Auth Request: %@", userAuthURL); + [self _authenticationRequestForUserPermissionsConfirmationAtURL:userAuthURL]; + } +} + +- (void)loader:(MPOAuthAPIRequestLoader *)inLoader didFailWithError:(NSError *)error { + if ([self.delegate respondsToSelector:@selector(authenticationDidFailWithError:)]) { + [self.delegate authenticationDidFailWithError: error]; + } +} + +- (void)_authenticationRequestForUserPermissionsConfirmationAtURL:(NSURL *)userAuthURL { +#if TARGET_OS_IPHONE + [[UIApplication sharedApplication] openURL:userAuthURL]; +#else + [[NSWorkspace sharedWorkspace] openURL:userAuthURL]; +#endif +} + +- (void)_authenticationRequestForAccessToken { + NSArray *params = nil; + + if (self.delegate && [self.delegate respondsToSelector: @selector(oauthVerifierForCompletedUserAuthorization)]) { + MPURLRequestParameter *verifierParameter = nil; + + NSString *verifier = [self.delegate oauthVerifierForCompletedUserAuthorization]; + if (verifier) { + verifierParameter = [[[MPURLRequestParameter alloc] initWithName:@"oauth_verifier" andValue:verifier] autorelease]; + params = [NSArray arrayWithObject:verifierParameter]; + } + } + + if (self.oauthGetAccessTokenURL) { + MPLog(@"--> Performing Access Token Request: %@", self.oauthGetAccessTokenURL); + [self.oauthAPI performMethod:nil atURL:self.oauthGetAccessTokenURL withParameters:params withTarget:self andAction:nil]; + } +} + +#pragma mark - + +- (void)_requestTokenReceived:(NSNotification *)inNotification { + if ([[inNotification userInfo] objectForKey:@"oauth_callback_confirmed"]) { + self.oauth10aModeActive = YES; + } + + [self.oauthAPI setCredential:[[inNotification userInfo] objectForKey:@"oauth_token"] withName:kMPOAuthCredentialRequestToken]; + [self.oauthAPI setCredential:[[inNotification userInfo] objectForKey:@"oauth_token_secret"] withName:kMPOAuthCredentialRequestTokenSecret]; +} + +- (void)_requestTokenRejected:(NSNotification *)inNotification { + [self.oauthAPI removeCredentialNamed:MPOAuthCredentialRequestTokenKey]; + [self.oauthAPI removeCredentialNamed:MPOAuthCredentialRequestTokenSecretKey]; +} + +- (void)_accessTokenReceived:(NSNotification *)inNotification { + [self.oauthAPI removeCredentialNamed:MPOAuthCredentialRequestTokenKey]; + [self.oauthAPI removeCredentialNamed:MPOAuthCredentialRequestTokenSecretKey]; + + [self.oauthAPI setCredential:[[inNotification userInfo] objectForKey:@"oauth_token"] withName:kMPOAuthCredentialAccessToken]; + [self.oauthAPI setCredential:[[inNotification userInfo] objectForKey:@"oauth_token_secret"] withName:kMPOAuthCredentialAccessTokenSecret]; + + if ([[inNotification userInfo] objectForKey:MPOAuthCredentialSessionHandleKey]) { + [self.oauthAPI setCredential:[[inNotification userInfo] objectForKey:MPOAuthCredentialSessionHandleKey] withName:kMPOAuthCredentialSessionHandle]; + } + + [self.oauthAPI setAuthenticationState:MPOAuthAuthenticationStateAuthenticated]; + + if ([[inNotification userInfo] objectForKey:@"oauth_expires_in"]) { + NSTimeInterval tokenRefreshInterval = (NSTimeInterval)[[[inNotification userInfo] objectForKey:@"oauth_expires_in"] intValue]; + NSDate *tokenExpiryDate = [NSDate dateWithTimeIntervalSinceNow:tokenRefreshInterval]; + [[NSUserDefaults standardUserDefaults] setDouble:[tokenExpiryDate timeIntervalSinceReferenceDate] forKey:MPOAuthTokenRefreshDateDefaultsKey]; + + if (tokenRefreshInterval > 0.0) { + [self setTokenRefreshInterval:tokenRefreshInterval]; + } + } else { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:MPOAuthTokenRefreshDateDefaultsKey]; + } +} + +#pragma mark - +#pragma mark - Private APIs - + +- (void)_performedLoad:(MPOAuthAPIRequestLoader *)inLoader receivingData:(NSData *)inData { + // NSLog(@"loaded %@, and got %@", inLoader, inData); +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthConnection.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthConnection.h new file mode 100644 index 0000000..71db8da --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthConnection.h @@ -0,0 +1,29 @@ +// +// MPOAuthConnection.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + +@protocol MPOAuthCredentialStore; +@protocol MPOAuthParameterFactory; + +@class MPOAuthURLRequest; +@class MPOAuthURLResponse; +@class MPOAuthCredentialConcreteStore; + +@interface MPOAuthConnection : NSURLConnection { +@private + MPOAuthCredentialConcreteStore *_credentials; +} + +@property (nonatomic, readonly) id credentials; + ++ (MPOAuthConnection *)connectionWithRequest:(MPOAuthURLRequest *)inRequest delegate:(id)inDelegate credentials:(NSObject *)inCredentials; ++ (NSData *)sendSynchronousRequest:(MPOAuthURLRequest *)inRequest usingCredentials:(NSObject *)inCredentials returningResponse:(MPOAuthURLResponse **)outResponse error:(NSError **)inError; +- (id)initWithRequest:(MPOAuthURLRequest *)inRequest delegate:(id)inDelegate credentials:(NSObject *)inCredentials; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthConnection.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthConnection.m new file mode 100644 index 0000000..3aeb0b3 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthConnection.m @@ -0,0 +1,58 @@ +// +// MPOAuthConnection.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthConnection.h" +#import "MPOAuthURLRequest.h" +#import "MPOAuthURLResponse.h" +#import "MPOAuthParameterFactory.h" +#import "MPOAuthCredentialConcreteStore.h" + +@interface MPOAuthURLResponse () +@property (nonatomic, readwrite, retain) NSURLResponse *urlResponse; +@property (nonatomic, readwrite, retain) NSDictionary *oauthParameters; +@end + +@implementation MPOAuthConnection + ++ (MPOAuthConnection *)connectionWithRequest:(MPOAuthURLRequest *)inRequest delegate:(id)inDelegate credentials:(NSObject *)inCredentials { + MPOAuthConnection *aConnection = [[MPOAuthConnection alloc] initWithRequest:inRequest delegate:inDelegate credentials:inCredentials]; + return [aConnection autorelease]; +} + ++ (NSData *)sendSynchronousRequest:(MPOAuthURLRequest *)inRequest usingCredentials:(NSObject *)inCredentials returningResponse:(MPOAuthURLResponse **)outResponse error:(NSError **)inError { + [inRequest addParameters:[inCredentials oauthParameters]]; + NSURLRequest *urlRequest = [inRequest urlRequestSignedWithSecret:[inCredentials signingKey] usingMethod:[inCredentials signatureMethod]]; + NSURLResponse *urlResponse = nil; + NSData *responseData = [self sendSynchronousRequest:urlRequest returningResponse:&urlResponse error:inError]; + MPOAuthURLResponse *oauthResponse = [[[MPOAuthURLResponse alloc] init] autorelease]; + oauthResponse.urlResponse = urlResponse; + *outResponse = oauthResponse; + + return responseData; +} + +- (id)initWithRequest:(MPOAuthURLRequest *)inRequest delegate:(id)inDelegate credentials:(NSObject *)inCredentials { + [inRequest addParameters:[inCredentials oauthParameters]]; + NSURLRequest *urlRequest = [inRequest urlRequestSignedWithSecret:[inCredentials signingKey] usingMethod:[inCredentials signatureMethod]]; + if (self = [super initWithRequest:urlRequest delegate:inDelegate]) { + _credentials = [inCredentials retain]; + } + return self; +} + +- (oneway void)dealloc { + [_credentials release]; + + [super dealloc]; +} + +@synthesize credentials = _credentials; + +#pragma mark - + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m new file mode 100644 index 0000000..8d4ed18 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m @@ -0,0 +1,89 @@ +// +// MPOAuthCredentialConcreteStore+TokenAdditionsMac.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.13. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthCredentialConcreteStore+KeychainAdditions.h" + +#if !TARGET_OS_IPHONE || (TARGET_IPHONE_SIMULATOR && !__IPHONE_3_0) + +@interface MPOAuthCredentialConcreteStore (KeychainAdditionsMac) +- (NSString *)findValueFromKeychainUsingName:(NSString *)inName returningItem:(SecKeychainItemRef *)outKeychainItemRef; +@end + +@implementation MPOAuthCredentialConcreteStore (KeychainAdditions) + +- (void)addToKeychainUsingName:(NSString *)inName andValue:(NSString *)inValue { + NSString *serverName = [self.baseURL host]; + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; + NSString *securityDomain = [self.authenticationURL host]; + NSString *uniqueName = [NSString stringWithFormat:@"%@.%@", bundleID, inName]; + SecKeychainItemRef existingKeychainItem = NULL; + + if ([self findValueFromKeychainUsingName:inName returningItem:&existingKeychainItem]) { + // This is MUCH easier than updating the item attributes/data + SecKeychainItemDelete(existingKeychainItem); + } + + SecKeychainAddInternetPassword(NULL /* default keychain */, + [serverName length], [serverName UTF8String], + [securityDomain length], [securityDomain UTF8String], + [uniqueName length], [uniqueName UTF8String], /* account name */ + 0, NULL, /* path */ + 0, + 'oaut' /* OAuth, not an official OSType code */, + kSecAuthenticationTypeDefault, + [inValue length], [inValue UTF8String], + NULL); +} + +- (NSString *)findValueFromKeychainUsingName:(NSString *)inName { + return [self findValueFromKeychainUsingName:inName returningItem:NULL]; +} + +- (NSString *)findValueFromKeychainUsingName:(NSString *)inName returningItem:(SecKeychainItemRef *)outKeychainItemRef { + NSString *foundPassword = nil; + NSString *serverName = [self.baseURL host]; + NSString *securityDomain = [self.authenticationURL host]; + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; + NSString *uniqueName = [NSString stringWithFormat:@"%@.%@", bundleID, inName]; + + UInt32 passwordLength = 0; + const char *passwordString = NULL; + + OSStatus status = SecKeychainFindInternetPassword(NULL /* default keychain */, + [serverName length], [serverName UTF8String], + [securityDomain length], [securityDomain UTF8String], + [uniqueName length], [uniqueName UTF8String], + 0, NULL, /* path */ + 0, + kSecProtocolTypeAny, + kSecAuthenticationTypeAny, + (UInt32 *)&passwordLength, + (void **)&passwordString, + outKeychainItemRef); + + if (status == noErr && passwordLength) { + NSData *passwordStringData = [NSData dataWithBytes:passwordString length:passwordLength]; + foundPassword = [[NSString alloc] initWithData:passwordStringData encoding:NSUTF8StringEncoding]; + } + + return [foundPassword autorelease]; +} + +- (void)removeValueFromKeychainUsingName:(NSString *)inName { + SecKeychainItemRef aKeychainItem = NULL; + + [self findValueFromKeychainUsingName:inName returningItem:&aKeychainItem]; + + if (aKeychainItem) { + SecKeychainItemDelete(aKeychainItem); + } +} + +@end + +#endif diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore+KeychainAdditions.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore+KeychainAdditions.h new file mode 100644 index 0000000..72d2c19 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore+KeychainAdditions.h @@ -0,0 +1,18 @@ +// +// MPOAuthCredentialConcreteStore+TokenAdditionsMac.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.13. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import +#import "MPOAuthCredentialConcreteStore.h" + +@interface MPOAuthCredentialConcreteStore (KeychainAdditions) + +- (void)addToKeychainUsingName:(NSString *)inName andValue:(NSString *)inValue; +- (NSString *)findValueFromKeychainUsingName:(NSString *)inName; +- (void)removeValueFromKeychainUsingName:(NSString *)inName; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m new file mode 100644 index 0000000..f1f4c15 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m @@ -0,0 +1,112 @@ +// +// MPOAuthCredentialConcreteStore+TokenAdditionsiPhone.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.13. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthCredentialConcreteStore+KeychainAdditions.h" +#import + +#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || __IPHONE_3_0) + +@interface MPOAuthCredentialConcreteStore (TokenAdditionsiPhone) +- (NSString *)findValueFromKeychainUsingName:(NSString *)inName returningItem:(NSDictionary **)outKeychainItemRef; +@end + +@implementation MPOAuthCredentialConcreteStore (KeychainAdditions) + +- (void)addToKeychainUsingName:(NSString *)inName andValue:(NSString *)inValue { + NSString *serverName = [self.baseURL host]; + NSString *securityDomain = [self.authenticationURL host]; +// NSString *itemID = [NSString stringWithFormat:@"%@.oauth.%@", [[NSBundle mainBundle] bundleIdentifier], inName]; + NSDictionary *searchDictionary = nil; + NSDictionary *keychainItemAttributeDictionary = [NSDictionary dictionaryWithObjectsAndKeys: (id)kSecClassInternetPassword, kSecClass, + securityDomain, kSecAttrSecurityDomain, + serverName, kSecAttrServer, + inName, kSecAttrAccount, + kSecAttrAuthenticationTypeDefault, kSecAttrAuthenticationType, + [NSNumber numberWithUnsignedLongLong:'oaut'], kSecAttrType, + [inValue dataUsingEncoding:NSUTF8StringEncoding], kSecValueData, + nil]; + + + if ([self findValueFromKeychainUsingName:inName returningItem:&searchDictionary]) { + NSMutableDictionary *updateDictionary = [keychainItemAttributeDictionary mutableCopy]; + [updateDictionary removeObjectForKey:(id)kSecClass]; + + SecItemUpdate((CFDictionaryRef)keychainItemAttributeDictionary, (CFDictionaryRef)updateDictionary); + [updateDictionary release]; + } else { + OSStatus success = SecItemAdd( (CFDictionaryRef)keychainItemAttributeDictionary, NULL); + + if (success == errSecNotAvailable) { + [NSException raise:@"Keychain Not Available" format:@"Keychain Access Not Currently Available"]; + } else if (success == errSecDuplicateItem) { + [NSException raise:@"Keychain duplicate item exception" format:@"Item already exists for %@", keychainItemAttributeDictionary]; + } + } +} + +- (NSString *)findValueFromKeychainUsingName:(NSString *)inName { + return [self findValueFromKeychainUsingName:inName returningItem:NULL]; +} + +- (NSString *)findValueFromKeychainUsingName:(NSString *)inName returningItem:(NSDictionary **)outKeychainItemRef { + NSString *foundPassword = nil; + NSString *serverName = [self.baseURL host]; + NSString *securityDomain = [self.authenticationURL host]; + NSDictionary *attributesDictionary = nil; + NSData *foundValue = nil; + OSStatus status = noErr; +// NSString *itemID = [NSString stringWithFormat:@"%@.oauth.%@", [[NSBundle mainBundle] bundleIdentifier], inName]; + + NSMutableDictionary *searchDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassInternetPassword, (id)kSecClass, + securityDomain, (id)kSecAttrSecurityDomain, + serverName, (id)kSecAttrServer, + inName, (id)kSecAttrAccount, + (id)kSecMatchLimitOne, (id)kSecMatchLimit, + (id)kCFBooleanTrue, (id)kSecReturnData, + (id)kCFBooleanTrue, (id)kSecReturnAttributes, + (id)kCFBooleanTrue, (id)kSecReturnPersistentRef, + nil]; + + status = SecItemCopyMatching((CFDictionaryRef)searchDictionary, (CFTypeRef *)&attributesDictionary); + foundValue = [attributesDictionary objectForKey:(id)kSecValueData]; + if (outKeychainItemRef) { + *outKeychainItemRef = attributesDictionary; + } + + if (status == noErr && foundValue) { + foundPassword = [[NSString alloc] initWithData:foundValue encoding:NSUTF8StringEncoding]; + } + + return [foundPassword autorelease]; +} + +- (void)removeValueFromKeychainUsingName:(NSString *)inName { + NSString *serverName = [self.baseURL host]; + NSString *securityDomain = [self.authenticationURL host]; + + NSMutableDictionary *searchDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys: (id)kSecClassInternetPassword, (id)kSecClass, + securityDomain, (id)kSecAttrSecurityDomain, + serverName, (id)kSecAttrServer, + inName, (id)kSecAttrAccount, + nil]; + + OSStatus success = SecItemDelete((CFDictionaryRef)searchDictionary); + + if (success == errSecNotAvailable) { + [NSException raise:@"Keychain Not Available" format:@"Keychain Access Not Currently Available"]; + } else if (success == errSecParam) { + [NSException raise:@"Keychain parameter error" format:@"One or more parameters passed to the function were not valid from %@", searchDictionary]; + } else if (success == errSecAllocate) { + [NSException raise:@"Keychain memory error" format:@"Failed to allocate memory"]; + } + +} + +@end + +#endif TARGET_OS_IPHONE diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore.h new file mode 100644 index 0000000..9906415 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore.h @@ -0,0 +1,40 @@ +// +// MPOAuthCredentialConcreteStore.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.11. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import +#import "MPOAuthCredentialStore.h" +#import "MPOAuthParameterFactory.h" + +@interface MPOAuthCredentialConcreteStore : NSObject { + NSMutableDictionary *store_; + NSURL *baseURL_; + NSURL *authenticationURL_; +} + +@property (nonatomic, readonly, retain) NSURL *baseURL; +@property (nonatomic, readonly, retain) NSURL *authenticationURL; + +@property (nonatomic, readonly) NSString *tokenSecret; +@property (nonatomic, readonly) NSString *signingKey; + +@property (nonatomic, readwrite, retain) NSString *requestToken; +@property (nonatomic, readwrite, retain) NSString *requestTokenSecret; +@property (nonatomic, readwrite, retain) NSString *accessToken; +@property (nonatomic, readwrite, retain) NSString *accessTokenSecret; + +@property (nonatomic, readwrite, retain) NSString *sessionHandle; + +- (id)initWithCredentials:(NSDictionary *)inCredential; +- (id)initWithCredentials:(NSDictionary *)inCredentials forBaseURL:(NSURL *)inBaseURL; +- (id)initWithCredentials:(NSDictionary *)inCredentials forBaseURL:(NSURL *)inBaseURL withAuthenticationURL:(NSURL *)inAuthenticationURL; + +- (void)setCredential:(id)inCredential withName:(NSString *)inName; +- (void)removeCredentialNamed:(NSString *)inName; + + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore.m new file mode 100644 index 0000000..87e0caa --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialConcreteStore.m @@ -0,0 +1,284 @@ +// +// MPOAuthCredentialConcreteStore.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.11. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthCredentialConcreteStore.h" +#import "MPURLRequestParameter.h" + +#import "MPOAuthCredentialConcreteStore+KeychainAdditions.h" +#import "NSString+URLEscapingAdditions.h" + +extern NSString * const MPOAuthCredentialRequestTokenKey; +extern NSString * const MPOAuthCredentialRequestTokenSecretKey; +extern NSString * const MPOAuthCredentialAccessTokenKey; +extern NSString * const MPOAuthCredentialAccessTokenSecretKey; +extern NSString * const MPOAuthCredentialSessionHandleKey; + +@interface MPOAuthCredentialConcreteStore () +@property (nonatomic, readwrite, retain) NSMutableDictionary *store; +@property (nonatomic, readwrite, retain) NSURL *baseURL; +@property (nonatomic, readwrite, retain) NSURL *authenticationURL; +@end + +@implementation MPOAuthCredentialConcreteStore + +- (id)initWithCredentials:(NSDictionary *)inCredentials { + return [self initWithCredentials:inCredentials forBaseURL:nil]; +} + +- (id)initWithCredentials:(NSDictionary *)inCredentials forBaseURL:(NSURL *)inBaseURL { + return [self initWithCredentials:inCredentials forBaseURL:inBaseURL withAuthenticationURL:inBaseURL]; +} + +- (id)initWithCredentials:(NSDictionary *)inCredentials forBaseURL:(NSURL *)inBaseURL withAuthenticationURL:(NSURL *)inAuthenticationURL { + if (self = [super init]) { + store_ = [[NSMutableDictionary alloc] initWithDictionary:inCredentials]; + self.baseURL = inBaseURL; + self.authenticationURL = inAuthenticationURL; + } + return self; +} + +- (oneway void)dealloc { + self.store = nil; + self.baseURL = nil; + self.authenticationURL = nil; + + [super dealloc]; +} + +@synthesize store = store_; +@synthesize baseURL = baseURL_; +@synthesize authenticationURL = authenticationURL_; + +#pragma mark - + +- (NSString *)consumerKey { + return [self.store objectForKey:kMPOAuthCredentialConsumerKey]; +} + +- (NSString *)consumerSecret { + return [self.store objectForKey:kMPOAuthCredentialConsumerSecret]; +} + +- (NSString *)username { + return [self.store objectForKey:kMPOAuthCredentialUsername]; +} + +- (NSString *)password { + return [self.store objectForKey:kMPOAuthCredentialPassword]; +} + +- (NSString *)requestToken { + return [self.store objectForKey:kMPOAuthCredentialRequestToken]; +} + +- (void)setRequestToken:(NSString *)inToken { + if (inToken) { + [self.store setObject:inToken forKey:kMPOAuthCredentialRequestToken]; + } else { + [self.store removeObjectForKey:kMPOAuthCredentialRequestToken]; + [self removeValueFromKeychainUsingName:kMPOAuthCredentialRequestToken]; + } +} + +- (NSString *)requestTokenSecret { + return [self.store objectForKey:kMPOAuthCredentialRequestTokenSecret]; +} + +- (void)setRequestTokenSecret:(NSString *)inTokenSecret { + if (inTokenSecret) { + [self.store setObject:inTokenSecret forKey:kMPOAuthCredentialRequestTokenSecret]; + } else { + [self.store removeObjectForKey:kMPOAuthCredentialRequestTokenSecret]; + [self removeValueFromKeychainUsingName:kMPOAuthCredentialRequestTokenSecret]; + } +} + +- (NSString *)accessToken { + return [self.store objectForKey:kMPOAuthCredentialAccessToken]; +} + +- (void)setAccessToken:(NSString *)inToken { + if (inToken) { + [self.store setObject:inToken forKey:kMPOAuthCredentialAccessToken]; + } else { + [self.store removeObjectForKey:kMPOAuthCredentialAccessToken]; + [self removeValueFromKeychainUsingName:kMPOAuthCredentialAccessToken]; + } +} + +- (NSString *)accessTokenSecret { + return [self.store objectForKey:kMPOAuthCredentialAccessTokenSecret]; +} + +- (void)setAccessTokenSecret:(NSString *)inTokenSecret { + if (inTokenSecret) { + [self.store setObject:inTokenSecret forKey:kMPOAuthCredentialAccessTokenSecret]; + } else { + [self.store removeObjectForKey:kMPOAuthCredentialAccessTokenSecret]; + [self removeValueFromKeychainUsingName:kMPOAuthCredentialAccessTokenSecret]; + } +} + +- (NSString *)sessionHandle { + return [self.store objectForKey:kMPOAuthCredentialSessionHandle]; +} + +- (void)setSessionHandle:(NSString *)inSessionHandle { + if (inSessionHandle) { + [self.store setObject:inSessionHandle forKey:kMPOAuthCredentialSessionHandle]; + } else { + [self.store removeObjectForKey:kMPOAuthCredentialSessionHandle]; + [self removeValueFromKeychainUsingName:kMPOAuthCredentialSessionHandle]; + } +} + +#pragma mark - + +- (NSString *)credentialNamed:(NSString *)inCredentialName { + return [store_ objectForKey:inCredentialName]; +} + +- (void)setCredential:(id)inCredential withName:(NSString *)inName { + [self.store setObject:inCredential forKey:inName]; + [self addToKeychainUsingName:inName andValue:inCredential]; +} + +- (void)removeCredentialNamed:(NSString *)inName { + [self.store removeObjectForKey:inName]; + [self removeValueFromKeychainUsingName:inName]; +} + +- (void)discardOAuthCredentials { + self.requestToken = nil; + self.requestTokenSecret = nil; + self.accessToken = nil; + self.accessTokenSecret = nil; + self.sessionHandle = nil; +} + +#pragma mark - + +- (NSString *)tokenSecret { + NSString *tokenSecret = @""; + + if (self.accessToken) { + tokenSecret = [self accessTokenSecret]; + } else if (self.requestToken) { + tokenSecret = [self requestTokenSecret]; + } + + return tokenSecret; +} + +- (NSString *)signingKey { + NSString *consumerSecret = [[self consumerSecret] stringByAddingURIPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + NSString *tokenSecret = [[self tokenSecret] stringByAddingURIPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + return [NSString stringWithFormat:@"%@%&%@", consumerSecret, tokenSecret]; +} + +#pragma mark - + +- (NSString *)timestamp { + return [NSString stringWithFormat:@"%d", (int)[[NSDate date] timeIntervalSince1970]]; +} + +- (NSString *)signatureMethod { + return [self.store objectForKey:kMPOAuthSignatureMethod]; +} + +- (NSArray *)oauthParameters { + NSMutableArray *oauthParameters = [[NSMutableArray alloc] initWithCapacity:5]; + MPURLRequestParameter *tokenParameter = [self oauthTokenParameter]; + + [oauthParameters addObject:[self oauthConsumerKeyParameter]]; + if (tokenParameter) [oauthParameters addObject:tokenParameter]; + [oauthParameters addObject:[self oauthSignatureMethodParameter]]; + [oauthParameters addObject:[self oauthTimestampParameter]]; + [oauthParameters addObject:[self oauthNonceParameter]]; + [oauthParameters addObject:[self oauthVersionParameter]]; + + return [oauthParameters autorelease]; +} + +- (void)setSignatureMethod:(NSString *)inSignatureMethod { + [self.store setObject:inSignatureMethod forKey:kMPOAuthSignatureMethod]; +} + +- (MPURLRequestParameter *)oauthConsumerKeyParameter { + MPURLRequestParameter *aRequestParameter = [[MPURLRequestParameter alloc] init]; + aRequestParameter.name = @"oauth_consumer_key"; + aRequestParameter.value = self.consumerKey; + + return [aRequestParameter autorelease]; +} + +- (MPURLRequestParameter *)oauthTokenParameter { + MPURLRequestParameter *aRequestParameter = nil; + + if (self.accessToken || self.requestToken) { + aRequestParameter = [[MPURLRequestParameter alloc] init]; + aRequestParameter.name = @"oauth_token"; + + if (self.accessToken) { + aRequestParameter.value = self.accessToken; + } else if (self.requestToken) { + aRequestParameter.value = self.requestToken; + } + } + + return [aRequestParameter autorelease]; +} + +- (MPURLRequestParameter *)oauthSignatureMethodParameter { + MPURLRequestParameter *aRequestParameter = [[MPURLRequestParameter alloc] init]; + aRequestParameter.name = @"oauth_signature_method"; + aRequestParameter.value = self.signatureMethod; + + return [aRequestParameter autorelease]; +} + +- (MPURLRequestParameter *)oauthTimestampParameter { + MPURLRequestParameter *aRequestParameter = [[MPURLRequestParameter alloc] init]; + aRequestParameter.name = @"oauth_timestamp"; + aRequestParameter.value = self.timestamp; + + return [aRequestParameter autorelease]; +} + +- (MPURLRequestParameter *)oauthNonceParameter { + MPURLRequestParameter *aRequestParameter = [[MPURLRequestParameter alloc] init]; + aRequestParameter.name = @"oauth_nonce"; + + NSString *generatedNonce = nil; + CFUUIDRef generatedUUID = CFUUIDCreate(kCFAllocatorDefault); + + generatedNonce = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, generatedUUID); + CFRelease(generatedUUID); + + aRequestParameter.value = generatedNonce; + [generatedNonce release]; + + return [aRequestParameter autorelease]; +} + +- (MPURLRequestParameter *)oauthVersionParameter { + MPURLRequestParameter *versionParameter = [self.store objectForKey:@"versionParameter"]; + + if (!versionParameter) { + versionParameter = [[MPURLRequestParameter alloc] init]; + versionParameter.name = @"oauth_version"; + versionParameter.value = @"1.0"; + [versionParameter autorelease]; + } + + return versionParameter; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialStore.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialStore.h new file mode 100644 index 0000000..27dbfaa --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthCredentialStore.h @@ -0,0 +1,33 @@ +// +// MPOAuthCredentialStore.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.06. +// Copyright 2008 matrixPointer. All rights reserved. +// + +extern NSString *kMPOAuthCredentialConsumerKey; +extern NSString *kMPOAuthCredentialConsumerSecret; +extern NSString *kMPOAuthCredentialUsername; +extern NSString *kMPOAuthCredentialPassword; +extern NSString *kMPOAuthCredentialRequestToken; +extern NSString *kMPOAuthCredentialRequestTokenSecret; +extern NSString *kMPOAuthCredentialAccessToken; +extern NSString *kMPOAuthCredentialAccessTokenSecret; +extern NSString *kMPOAuthCredentialSessionHandle; +extern NSString *kMPOAuthCredentialRealm; + +@protocol MPOAuthCredentialStore + +@property (nonatomic, readonly) NSString *consumerKey; +@property (nonatomic, readonly) NSString *consumerSecret; +@property (nonatomic, readonly) NSString *username; +@property (nonatomic, readonly) NSString *password; +@property (nonatomic, readonly, retain) NSString *requestToken; +@property (nonatomic, readonly, retain) NSString *requestTokenSecret; +@property (nonatomic, readonly, retain) NSString *accessToken; +@property (nonatomic, readonly, retain) NSString *accessTokenSecret; + +- (NSString *)credentialNamed:(NSString *)inCredentialName; +- (void)discardOAuthCredentials; +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthParameterFactory.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthParameterFactory.h new file mode 100644 index 0000000..7d75ca3 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthParameterFactory.h @@ -0,0 +1,28 @@ +// +// MPOAuthParameterFactory.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.06. +// Copyright 2008 matrixPointer. All rights reserved. +// + +extern NSString *kMPOAuthSignatureMethod; + +@class MPURLRequestParameter; + +@protocol MPOAuthParameterFactory + +@property (nonatomic, readwrite, retain) NSString *signatureMethod; +@property (nonatomic, readonly) NSString *signingKey; +@property (nonatomic, readonly) NSString *timestamp; + +- (NSArray *)oauthParameters; + +- (MPURLRequestParameter *)oauthConsumerKeyParameter; +- (MPURLRequestParameter *)oauthTokenParameter; +- (MPURLRequestParameter *)oauthSignatureMethodParameter; +- (MPURLRequestParameter *)oauthTimestampParameter; +- (MPURLRequestParameter *)oauthNonceParameter; +- (MPURLRequestParameter *)oauthVersionParameter; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthSignatureParameter.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthSignatureParameter.h new file mode 100644 index 0000000..08ec7c5 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthSignatureParameter.h @@ -0,0 +1,28 @@ +// +// MPOAuthSignatureParameter.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.07. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import +#import "MPURLRequestParameter.h" + +#define kMPOAuthSignatureMethodPlaintext @"PLAINTEXT" +#define kMPOAuthSignatureMethodHMACSHA1 @"HMAC-SHA1" +#define kMPOAuthSignatureMethodRSASHA1 @"RSA-SHA1" + +@class MPOAuthURLRequest; + +@interface MPOAuthSignatureParameter : MPURLRequestParameter { + +} + ++ (NSString *)signatureBaseStringUsingParameterString:(NSString *)inParameterString forRequest:(MPOAuthURLRequest *)inRequest; ++ (NSString *)HMAC_SHA1SignatureForText:(NSString *)inText usingSecret:(NSString *)inSecret; + +- (id)initWithText:(NSString *)inText andSecret:(NSString *)inSecret forRequest:(MPOAuthURLRequest *)inRequest usingMethod:(NSString *)inMethod; + + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthSignatureParameter.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthSignatureParameter.m new file mode 100644 index 0000000..b0b3538 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthSignatureParameter.m @@ -0,0 +1,81 @@ +// +// MPOAuthSignatureParameter.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.07. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthSignatureParameter.h" +#import "MPOAuthURLRequest.h" +#import "NSString+URLEscapingAdditions.h" +#import "NSURL+MPURLParameterAdditions.h" + +#import +#include "Base64Transcoder.h" + +@interface MPOAuthSignatureParameter () +- (id)initUsingHMAC_SHA1WithText:(NSString *)inText andSecret:(NSString *)inSecret forRequest:(MPOAuthURLRequest *)inRequest; +@end + +@implementation MPOAuthSignatureParameter + ++ (NSString *)signatureBaseStringUsingParameterString:(NSString *)inParameterString forRequest:(MPOAuthURLRequest *)inRequest { + return [NSString stringWithFormat:@"%@&%@&%@", [inRequest HTTPMethod], + [[inRequest.url absoluteNormalizedString] stringByAddingURIPercentEscapesUsingEncoding:NSUTF8StringEncoding], + [inParameterString stringByAddingURIPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; +} + ++ (NSString *)HMAC_SHA1SignatureForText:(NSString *)inText usingSecret:(NSString *)inSecret { + NSData *secretData = [inSecret dataUsingEncoding:NSUTF8StringEncoding]; + NSData *textData = [inText dataUsingEncoding:NSUTF8StringEncoding]; + unsigned char result[CC_SHA1_DIGEST_LENGTH]; + + CCHmacContext hmacContext; + bzero(&hmacContext, sizeof(CCHmacContext)); + CCHmacInit(&hmacContext, kCCHmacAlgSHA1, secretData.bytes, secretData.length); + CCHmacUpdate(&hmacContext, textData.bytes, textData.length); + CCHmacFinal(&hmacContext, result); + + //Base64 Encoding + char base64Result[32]; + size_t theResultLength = 32; + Base64EncodeData(result, 20, base64Result, &theResultLength); + NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength]; + NSString *base64EncodedResult = [[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease]; + + return base64EncodedResult; +} + +- (id)initWithText:(NSString *)inText andSecret:(NSString *)inSecret forRequest:(MPOAuthURLRequest *)inRequest usingMethod:(NSString *)inMethod { + if ([inMethod isEqual:kMPOAuthSignatureMethodHMACSHA1]) { + self = [self initUsingHMAC_SHA1WithText:inText andSecret:inSecret forRequest:inRequest]; + } else if ([inMethod isEqualToString:kMPOAuthSignatureMethodPlaintext]) { + if (self = [super init]) { + self.name = @"oauth_signature"; + self.value = inSecret; + } + } else { + [self release]; + self = nil; + [NSException raise:@"Unsupported Signature Method" format:@"The signature method \"%@\" is not currently support by MPOAuthConnection", inMethod]; + } + + return self; +} + +- (id)initUsingHMAC_SHA1WithText:(NSString *)inText andSecret:(NSString *)inSecret forRequest:(MPOAuthURLRequest *)inRequest { + if (self = [super init]) { + NSString *signatureBaseString = [MPOAuthSignatureParameter signatureBaseStringUsingParameterString:inText forRequest:inRequest]; + + self.name = @"oauth_signature"; + self.value = [MPOAuthSignatureParameter HMAC_SHA1SignatureForText:signatureBaseString usingSecret:inSecret]; + } + return self; +} + +- (oneway void)dealloc { + [super dealloc]; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLRequest.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLRequest.h new file mode 100644 index 0000000..0ad4b3e --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLRequest.h @@ -0,0 +1,32 @@ +// +// MPOAuthURLRequest.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + + +@interface MPOAuthURLRequest : NSObject { +@private + NSURL *_url; + NSString *_httpMethod; + NSURLRequest *_urlRequest; + NSMutableArray *_parameters; +} + +@property (nonatomic, readwrite, retain) NSURL *url; +@property (nonatomic, readwrite, retain) NSString *HTTPMethod; +@property (nonatomic, readonly, retain) NSURLRequest *urlRequest; +@property (nonatomic, readwrite, retain) NSMutableArray *parameters; + +- (id)initWithURL:(NSURL *)inURL andParameters:(NSArray *)parameters; +- (id)initWithURLRequest:(NSURLRequest *)inRequest; + +- (void)addParameters:(NSArray *)inParameters; + +- (NSMutableURLRequest*)urlRequestSignedWithSecret:(NSString *)inSecret usingMethod:(NSString *)inScheme; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLRequest.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLRequest.m new file mode 100644 index 0000000..a4430e4 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLRequest.m @@ -0,0 +1,100 @@ +// +// MPOAuthURLRequest.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthURLRequest.h" +#import "MPURLRequestParameter.h" +#import "MPOAuthSignatureParameter.h" +#import "MPDebug.h" + +#import "NSURL+MPURLParameterAdditions.h" +#import "NSString+URLEscapingAdditions.h" + +@interface MPOAuthURLRequest () +@property (nonatomic, readwrite, retain) NSURLRequest *urlRequest; +@end + +@implementation MPOAuthURLRequest + +- (id)initWithURL:(NSURL *)inURL andParameters:(NSArray *)inParameters { + if (self = [super init]) { + self.url = inURL; + _parameters = inParameters ? [inParameters mutableCopy] : [[NSMutableArray alloc] initWithCapacity:10]; + self.HTTPMethod = @"GET"; + } + return self; +} + +- (id)initWithURLRequest:(NSURLRequest *)inRequest { + if (self = [super init]) { + self.url = [[inRequest URL] urlByRemovingQuery]; + self.parameters = [[MPURLRequestParameter parametersFromString:[[inRequest URL] query]] mutableCopy]; + self.HTTPMethod = [inRequest HTTPMethod]; + } + return self; +} + +- (oneway void)dealloc { + self.url = nil; + self.HTTPMethod = nil; + self.urlRequest = nil; + self.parameters = nil; + + [super dealloc]; +} + +@synthesize url = _url; +@synthesize HTTPMethod = _httpMethod; +@synthesize urlRequest = _urlRequest; +@synthesize parameters = _parameters; + +#pragma mark - + +- (NSMutableURLRequest*)urlRequestSignedWithSecret:(NSString *)inSecret usingMethod:(NSString *)inScheme { + [self.parameters sortUsingSelector:@selector(compare:)]; + + NSMutableURLRequest *aRequest = [[NSMutableURLRequest alloc] init]; + NSMutableString *parameterString = [[NSMutableString alloc] initWithString:[MPURLRequestParameter parameterStringForParameters:self.parameters]]; + MPOAuthSignatureParameter *signatureParameter = [[MPOAuthSignatureParameter alloc] initWithText:parameterString andSecret:inSecret forRequest:self usingMethod:inScheme]; + [parameterString appendFormat:@"&%@", [signatureParameter URLEncodedParameterString]]; + + [aRequest setHTTPMethod:self.HTTPMethod]; + + if ([[self HTTPMethod] isEqualToString:@"GET"] && [self.parameters count]) { + NSString *urlString = [NSString stringWithFormat:@"%@?%@", [self.url absoluteString], parameterString]; + MPLog( @"urlString - %@", urlString); + + [aRequest setURL:[NSURL URLWithString:urlString]]; + } else if ([[self HTTPMethod] isEqualToString:@"POST"]) { + NSData *postData = [parameterString dataUsingEncoding:NSUTF8StringEncoding]; + MPLog(@"urlString - %@", self.url); + MPLog(@"postDataString - %@", parameterString); + + [aRequest setURL:self.url]; + [aRequest setValue:[NSString stringWithFormat:@"%d", [postData length]] forHTTPHeaderField:@"Content-Length"]; + [aRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + [aRequest setHTTPBody:postData]; + } else { + [NSException raise:@"UnhandledHTTPMethodException" format:@"The requested HTTP method, %@, is not supported", self.HTTPMethod]; + } + + [parameterString release]; + [signatureParameter release]; + + self.urlRequest = aRequest; + [aRequest release]; + + return aRequest; +} + +#pragma mark - + +- (void)addParameters:(NSArray *)inParameters { + [self.parameters addObjectsFromArray:inParameters]; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLResponse.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLResponse.h new file mode 100644 index 0000000..c3c5cc6 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLResponse.h @@ -0,0 +1,20 @@ +// +// MPOAuthURLResponse.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + + +@interface MPOAuthURLResponse : NSObject { + NSURLResponse *_urlResponse; + NSDictionary *_oauthParameters; +} + +@property (nonatomic, readonly, retain) NSURLResponse *urlResponse; +@property (nonatomic, readonly, retain) NSDictionary *oauthParameters; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLResponse.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLResponse.m new file mode 100644 index 0000000..73c87a3 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPOAuthURLResponse.m @@ -0,0 +1,35 @@ +// +// MPOAuthURLResponse.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPOAuthURLResponse.h" + +@interface MPOAuthURLResponse () +@property (nonatomic, readwrite, retain) NSURLResponse *urlResponse; +@property (nonatomic, readwrite, retain) NSDictionary *oauthParameters; +@end + +@implementation MPOAuthURLResponse + +- (id)init { + if (self = [super init]) { + + } + return self; +} + +- (oneway void)dealloc { + self.urlResponse = nil; + self.oauthParameters = nil; + + [super dealloc]; +} + +@synthesize urlResponse = _urlResponse; +@synthesize oauthParameters = _oauthParameters; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPURLRequestParameter.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPURLRequestParameter.h new file mode 100644 index 0000000..36e53bc --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPURLRequestParameter.h @@ -0,0 +1,30 @@ +// +// MPURLParameter.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + + +@interface MPURLRequestParameter : NSObject { + NSString *_name; + NSString *_value; +} + +@property (nonatomic, readwrite, copy) NSString *name; +@property (nonatomic, readwrite, copy) NSString *value; + ++ (NSArray *)parametersFromString:(NSString *)inString; ++ (NSArray *)parametersFromDictionary:(NSDictionary *)inDictionary; ++ (NSDictionary *)parameterDictionaryFromString:(NSString *)inString; ++ (NSString *)parameterStringForParameters:(NSArray *)inParameters; ++ (NSString *)parameterStringForDictionary:(NSDictionary *)inParameterDictionary; + +- (id)initWithName:(NSString *)inName andValue:(NSString *)inValue; + +- (NSString *)URLEncodedParameterString; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/MPURLRequestParameter.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPURLRequestParameter.m new file mode 100644 index 0000000..64b811f --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/MPURLRequestParameter.m @@ -0,0 +1,158 @@ +// +// MPURLParameter.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "MPURLRequestParameter.h" +#import "NSString+URLEscapingAdditions.h" + +@implementation MPURLRequestParameter + ++ (NSArray *)parametersFromString:(NSString *)inString { + NSMutableArray *foundParameters = [NSMutableArray arrayWithCapacity:10]; + NSScanner *parameterScanner = [[NSScanner alloc] initWithString:inString]; + NSString *name = nil; + NSString *value = nil; + MPURLRequestParameter *currentParameter = nil; + + while (![parameterScanner isAtEnd]) { + name = nil; + value = nil; + + [parameterScanner scanUpToString:@"=" intoString:&name]; + [parameterScanner scanString:@"=" intoString:NULL]; + [parameterScanner scanUpToString:@"&" intoString:&value]; + [parameterScanner scanString:@"&" intoString:NULL]; + + currentParameter = [[MPURLRequestParameter alloc] init]; + currentParameter.name = name; + currentParameter.value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + [foundParameters addObject:currentParameter]; + + [currentParameter release]; + } + + [parameterScanner release]; + + return foundParameters; +} + ++ (NSArray *)parametersFromDictionary:(NSDictionary *)inDictionary { + NSMutableArray *parameterArray = [[NSMutableArray alloc] init]; + MPURLRequestParameter *aURLParameter = nil; + + for (NSString *aKey in [inDictionary allKeys]) { + aURLParameter = [[MPURLRequestParameter alloc] init]; + aURLParameter.name = aKey; + aURLParameter.value = [inDictionary objectForKey:aKey]; + + [parameterArray addObject:aURLParameter]; + [aURLParameter release]; + } + + return [parameterArray autorelease]; +} + ++ (NSDictionary *)parameterDictionaryFromString:(NSString *)inString { + NSMutableDictionary *foundParameters = [NSMutableDictionary dictionaryWithCapacity:10]; + if (inString) { + NSScanner *parameterScanner = [[NSScanner alloc] initWithString:inString]; + NSString *name = nil; + NSString *value = nil; + + while (![parameterScanner isAtEnd]) { + name = nil; + value = nil; + + [parameterScanner scanUpToString:@"=" intoString:&name]; + [parameterScanner scanString:@"=" intoString:NULL]; + [parameterScanner scanUpToString:@"&" intoString:&value]; + [parameterScanner scanString:@"&" intoString:NULL]; + + [foundParameters setObject:[value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:name]; + } + + [parameterScanner release]; + } + return foundParameters; +} + ++ (NSString *)parameterStringForParameters:(NSArray *)inParameters { + NSMutableString *queryString = [[NSMutableString alloc] init]; + int i = 0; + int parameterCount = [inParameters count]; + MPURLRequestParameter *aParameter = nil; + + for (; i < parameterCount; i++) { + aParameter = [inParameters objectAtIndex:i]; + [queryString appendString:[aParameter URLEncodedParameterString]]; + + if (i < parameterCount - 1) { + [queryString appendString:@"&"]; + } + } + + return [queryString autorelease]; +} + ++ (NSString *)parameterStringForDictionary:(NSDictionary *)inParameterDictionary { + NSArray *parameters = [self parametersFromDictionary:inParameterDictionary]; + NSString *queryString = [self parameterStringForParameters:parameters]; + + return queryString; +} + +#pragma mark - + +- (id)init { + if (self = [super init]) { + + } + return self; +} + +- (id)initWithName:(NSString *)inName andValue:(NSString *)inValue { + if (self = [super init]) { + self.name = inName; + self.value = inValue; + } + return self; +} + +- (oneway void)dealloc { + self.name = nil; + self.value = nil; + + [super dealloc]; +} + +@synthesize name = _name; +@synthesize value = _value; + +#pragma mark - + +- (NSString *)URLEncodedParameterString { + return [NSString stringWithFormat:@"%@=%@", [self.name stringByAddingURIPercentEscapesUsingEncoding:NSUTF8StringEncoding], self.value ? [self.value stringByAddingURIPercentEscapesUsingEncoding:NSUTF8StringEncoding] : @""]; +} + +#pragma mark - + +- (NSComparisonResult)compare:(id)inObject { + NSComparisonResult result = [self.name compare:[(MPURLRequestParameter *)inObject name]]; + + if (result == NSOrderedSame) { + result = [self.value compare:[(MPURLRequestParameter *)inObject value]]; + } + + return result; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p %@>", NSStringFromClass([self class]), self, [self URLEncodedParameterString]]; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/NSString+URLEscapingAdditions.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSString+URLEscapingAdditions.h new file mode 100644 index 0000000..9be93a4 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSString+URLEscapingAdditions.h @@ -0,0 +1,21 @@ +// +// NSString+URLEscapingAdditions.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.07. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + + +@interface NSString (MPURLEscapingAdditions) + +- (BOOL)isIPAddress; +- (NSString *)stringByAddingURIPercentEscapesUsingEncoding:(NSStringEncoding)inEncoding; + +@end + +@interface NSURL (MPURLEscapingAdditions) +- (NSString *)stringByAddingURIPercentEscapesUsingEncoding:(NSStringEncoding)inEncoding; +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/NSString+URLEscapingAdditions.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSString+URLEscapingAdditions.m new file mode 100644 index 0000000..a5d4587 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSString+URLEscapingAdditions.m @@ -0,0 +1,60 @@ +// +// NSString+URLEscapingAdditions.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.07. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "NSString+URLEscapingAdditions.h" + + +@implementation NSString (MPURLEscapingAdditions) + +- (BOOL)isIPAddress { + BOOL isIPAddress = NO; + NSArray *components = [self componentsSeparatedByString:@"."]; + NSCharacterSet *invalidCharacters = [[NSCharacterSet characterSetWithCharactersInString:@"1234567890"] invertedSet]; + + if ([components count] == 4) { + NSString *part1 = [components objectAtIndex:0]; + NSString *part2 = [components objectAtIndex:1]; + NSString *part3 = [components objectAtIndex:2]; + NSString *part4 = [components objectAtIndex:3]; + + if ([part1 rangeOfCharacterFromSet:invalidCharacters].location == NSNotFound && + [part2 rangeOfCharacterFromSet:invalidCharacters].location == NSNotFound && + [part3 rangeOfCharacterFromSet:invalidCharacters].location == NSNotFound && + [part4 rangeOfCharacterFromSet:invalidCharacters].location == NSNotFound ) { + + if ([part1 intValue] < 255 && + [part2 intValue] < 255 && + [part3 intValue] < 255 && + [part4 intValue] < 255) { + isIPAddress = YES; + } + } + } + + return isIPAddress; +} + +- (NSString *)stringByAddingURIPercentEscapesUsingEncoding:(NSStringEncoding)inEncoding { + NSString *escapedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)self, + NULL, + (CFStringRef)@":/?=,!$&'()*+;[]@#", + CFStringConvertNSStringEncodingToEncoding(inEncoding)); + + return [escapedString autorelease]; +} + +@end + +@implementation NSURL (MPURLEscapingAdditions) + +- (NSString *)stringByAddingURIPercentEscapesUsingEncoding:(NSStringEncoding)inEncoding { + return [[self absoluteString] stringByAddingURIPercentEscapesUsingEncoding:inEncoding]; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURL+MPURLParameterAdditions.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURL+MPURLParameterAdditions.h new file mode 100644 index 0000000..cea636d --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURL+MPURLParameterAdditions.h @@ -0,0 +1,21 @@ +// +// NSURL+MPURLParameterAdditions.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.08. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + + +@interface NSURL (MPURLParameterAdditions) + +- (NSURL *)urlByAddingParameters:(NSArray *)inParameters; +- (NSURL *)urlByAddingParameterDictionary:(NSDictionary *)inParameters; +- (NSURL *)urlByRemovingQuery; +- (NSString *)absoluteNormalizedString; + +- (BOOL)domainMatches:(NSString *)inString; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURL+MPURLParameterAdditions.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURL+MPURLParameterAdditions.m new file mode 100644 index 0000000..aca3286 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURL+MPURLParameterAdditions.m @@ -0,0 +1,98 @@ +// +// NSURL+MPURLParameterAdditions.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.08. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "NSURL+MPURLParameterAdditions.h" +#import "MPURLRequestParameter.h" +#import "NSString+URLEscapingAdditions.h" + +@implementation NSURL (MPURLParameterAdditions) + +- (NSURL *)urlByAddingParameters:(NSArray *)inParameters { + NSMutableArray *parameters = [[NSMutableArray alloc] init]; + NSString *queryString = [self query]; + NSString *absoluteString = [self absoluteString]; + NSRange parameterRange = [absoluteString rangeOfString:@"?"]; + + if (parameterRange.location != NSNotFound) { + parameterRange.length = [absoluteString length] - parameterRange.location; + [parameters addObjectsFromArray:[MPURLRequestParameter parametersFromString:queryString]]; + absoluteString = [absoluteString substringToIndex:parameterRange.location]; + } + + [parameters addObjectsFromArray:inParameters]; + + return [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", absoluteString, [MPURLRequestParameter parameterStringForParameters:[parameters autorelease]]]]; +} + +- (NSURL *)urlByAddingParameterDictionary:(NSDictionary *)inParameterDictionary { + NSMutableDictionary *parameterDictionary = [inParameterDictionary mutableCopy]; + NSString *queryString = [self query]; + NSString *absoluteString = [self absoluteString]; + NSRange parameterRange = [absoluteString rangeOfString:@"?"]; + NSURL *composedURL = self; + + if (parameterRange.location != NSNotFound) { + parameterRange.length = [absoluteString length] - parameterRange.location; + + //[parameterDictionary addEntriesFromDictionary:inParameterDictionary]; + [parameterDictionary addEntriesFromDictionary:[MPURLRequestParameter parameterDictionaryFromString:queryString]]; + + composedURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", [absoluteString substringToIndex:parameterRange.location], [MPURLRequestParameter parameterStringForDictionary:parameterDictionary]]]; + } else if ([parameterDictionary count]) { + composedURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", absoluteString, [MPURLRequestParameter parameterStringForDictionary:parameterDictionary]]]; + } + + [parameterDictionary release]; + + return composedURL; +} + +- (NSURL *)urlByRemovingQuery { + NSURL *composedURL = self; + NSString *absoluteString = [self absoluteString]; + NSRange queryRange = [absoluteString rangeOfString:@"?"]; + + if (queryRange.location != NSNotFound) { + NSString *urlSansQuery = [absoluteString substringToIndex:queryRange.location]; + composedURL = [NSURL URLWithString:urlSansQuery]; + } + + return composedURL; +} + +- (NSString *)absoluteNormalizedString { + NSString *normalizedString = [self absoluteString]; + + if ([[self path] length] == 0 && [[self query] length] == 0) { + normalizedString = [NSString stringWithFormat:@"%@/", [self absoluteString]]; + } + + return normalizedString; +} + +- (BOOL)domainMatches:(NSString *)inString { + BOOL matches = NO; + + NSString *domain = [self host]; + matches = [domain isIPAddress] && [domain isEqualToString:inString]; + + int domainLength = [domain length]; + int requestedDomainLength = [inString length]; + + if (!matches) { + if (domainLength > requestedDomainLength) { + matches = [domain rangeOfString:inString].location == (domainLength - requestedDomainLength); + } else if (domainLength == (requestedDomainLength - 1)) { + matches = ([inString compare:domain options:NSCaseInsensitiveSearch range:NSMakeRange(1, domainLength)] == NSOrderedSame); + } + } + + return matches; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURLResponse+Encoding.h b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURLResponse+Encoding.h new file mode 100644 index 0000000..40699ef --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURLResponse+Encoding.h @@ -0,0 +1,14 @@ +// +// NSURL+MPEncodingAdditions.h +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import + + +@interface NSURLResponse (EncodingAdditions) +- (NSStringEncoding)encoding; +@end diff --git a/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURLResponse+Encoding.m b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURLResponse+Encoding.m new file mode 100644 index 0000000..beab278 --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/MPOAuth/NSURLResponse+Encoding.m @@ -0,0 +1,27 @@ +// +// NSURL+MPEncodingAdditions.m +// MPOAuthConnection +// +// Created by Karl Adam on 08.12.05. +// Copyright 2008 matrixPointer. All rights reserved. +// + +#import "NSURLResponse+Encoding.h" + + +@implementation NSURLResponse (EncodingAdditions) + +- (NSStringEncoding)encoding { + NSStringEncoding encoding = NSUTF8StringEncoding; + + if ([self textEncodingName]) { + CFStringEncoding cfStringEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)[self textEncodingName]); + if (cfStringEncoding != kCFStringEncodingInvalidId) { + encoding = CFStringConvertEncodingToNSStringEncoding(cfStringEncoding); + } + } + + return encoding; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/NSString+Dropbox.h b/Classes/ThirdParty/DropboxSDK/NSString+Dropbox.h new file mode 100644 index 0000000..c261f4a --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/NSString+Dropbox.h @@ -0,0 +1,18 @@ +// +// NSString+Dropbox.h +// DropboxSDK +// +// Created by Brian Smith on 7/19/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + + +@interface NSString (Dropbox) + +// This will take a path for a resource and normalize so you can compare paths +- (NSString*)normalizedDropboxPath; + +// Normalizes both paths and compares them +- (BOOL)isEqualToDropboxPath:(NSString*)otherPath; + +@end diff --git a/Classes/ThirdParty/DropboxSDK/NSString+Dropbox.m b/Classes/ThirdParty/DropboxSDK/NSString+Dropbox.m new file mode 100644 index 0000000..ef665ce --- /dev/null +++ b/Classes/ThirdParty/DropboxSDK/NSString+Dropbox.m @@ -0,0 +1,23 @@ +// +// NSString+Dropbox.m +// DropboxSDK +// +// Created by Brian Smith on 7/19/10. +// Copyright 2010 Dropbox, Inc. All rights reserved. +// + +#import "NSString+Dropbox.h" + + +@implementation NSString (Dropbox) + +- (NSString*)normalizedDropboxPath { + if ([self isEqual:@"/"]) return @""; + return [[self lowercaseString] precomposedStringWithCanonicalMapping]; +} + +- (BOOL)isEqualToDropboxPath:(NSString*)otherPath { + return [[self normalizedDropboxPath] isEqualToString:[otherPath normalizedDropboxPath]]; +} + +@end diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_background.png b/Classes/ThirdParty/DropboxSDK/Resources/db_background.png new file mode 100644 index 0000000..dbb153b Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_background.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_create_account.png b/Classes/ThirdParty/DropboxSDK/Resources/db_create_account.png new file mode 100644 index 0000000..5e1ee15 Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_create_account.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_create_account@2x.png b/Classes/ThirdParty/DropboxSDK/Resources/db_create_account@2x.png new file mode 100644 index 0000000..80e2d6a Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_create_account@2x.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_create_account_button.png b/Classes/ThirdParty/DropboxSDK/Resources/db_create_account_button.png new file mode 100644 index 0000000..f382dd9 Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_create_account_button.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_create_account_button_down.png b/Classes/ThirdParty/DropboxSDK/Resources/db_create_account_button_down.png new file mode 100644 index 0000000..9c56b98 Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_create_account_button_down.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_link_button.png b/Classes/ThirdParty/DropboxSDK/Resources/db_link_button.png new file mode 100644 index 0000000..3e14fe0 Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_link_button.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_link_button_down.png b/Classes/ThirdParty/DropboxSDK/Resources/db_link_button_down.png new file mode 100644 index 0000000..04d9fbb Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_link_button_down.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_link_header.png b/Classes/ThirdParty/DropboxSDK/Resources/db_link_header.png new file mode 100644 index 0000000..becf020 Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_link_header.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_link_header@2x.png b/Classes/ThirdParty/DropboxSDK/Resources/db_link_header@2x.png new file mode 100644 index 0000000..ef1a330 Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_link_header@2x.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_logo.png b/Classes/ThirdParty/DropboxSDK/Resources/db_logo.png new file mode 100644 index 0000000..4c3b6c2 Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_logo.png differ diff --git a/Classes/ThirdParty/DropboxSDK/Resources/db_logo@2x.png b/Classes/ThirdParty/DropboxSDK/Resources/db_logo@2x.png new file mode 100644 index 0000000..b9f1cb2 Binary files /dev/null and b/Classes/ThirdParty/DropboxSDK/Resources/db_logo@2x.png differ diff --git a/TKLabelCell.h b/Classes/ThirdParty/Tapku/TKLabelCell.h similarity index 100% rename from TKLabelCell.h rename to Classes/ThirdParty/Tapku/TKLabelCell.h diff --git a/TKLabelCell.m b/Classes/ThirdParty/Tapku/TKLabelCell.m similarity index 100% rename from TKLabelCell.m rename to Classes/ThirdParty/Tapku/TKLabelCell.m diff --git a/TKLabelTextFieldCell.h b/Classes/ThirdParty/Tapku/TKLabelTextFieldCell.h similarity index 100% rename from TKLabelTextFieldCell.h rename to Classes/ThirdParty/Tapku/TKLabelTextFieldCell.h diff --git a/TKLabelTextFieldCell.m b/Classes/ThirdParty/Tapku/TKLabelTextFieldCell.m similarity index 100% rename from TKLabelTextFieldCell.m rename to Classes/ThirdParty/Tapku/TKLabelTextFieldCell.m diff --git a/TKTextViewCell.h b/Classes/ThirdParty/Tapku/TKTextViewCell.h similarity index 100% rename from TKTextViewCell.h rename to Classes/ThirdParty/Tapku/TKTextViewCell.h diff --git a/TKTextViewCell.m b/Classes/ThirdParty/Tapku/TKTextViewCell.m similarity index 100% rename from TKTextViewCell.m rename to Classes/ThirdParty/Tapku/TKTextViewCell.m diff --git a/TextFieldCell.h b/Classes/ThirdParty/Tapku/TextFieldCell.h similarity index 100% rename from TextFieldCell.h rename to Classes/ThirdParty/Tapku/TextFieldCell.h diff --git a/TextFieldCell.m b/Classes/ThirdParty/Tapku/TextFieldCell.m similarity index 100% rename from TextFieldCell.m rename to Classes/ThirdParty/Tapku/TextFieldCell.m diff --git a/AboutViewController.h b/Classes/UI/AboutViewController.h similarity index 100% rename from AboutViewController.h rename to Classes/UI/AboutViewController.h diff --git a/AboutViewController.m b/Classes/UI/AboutViewController.m similarity index 100% rename from AboutViewController.m rename to Classes/UI/AboutViewController.m diff --git a/ActivityView.h b/Classes/UI/ActivityView.h similarity index 100% rename from ActivityView.h rename to Classes/UI/ActivityView.h diff --git a/ActivityView.m b/Classes/UI/ActivityView.m similarity index 100% rename from ActivityView.m rename to Classes/UI/ActivityView.m diff --git a/FileManager.h b/Classes/UI/FileManager.h similarity index 64% rename from FileManager.h rename to Classes/UI/FileManager.h index 205b220..b5b41d6 100644 --- a/FileManager.h +++ b/Classes/UI/FileManager.h @@ -8,33 +8,47 @@ #import #import +#import "DropboxSDK.h" #define KDB_VERSION1 1 #define KDB_VERSION2 2 -@interface FileManager : NSObject { +@class DBRestClient; +@class PasswordViewController; + +@interface FileManager : NSObject { //e.g. test.kdb; directory information is not included; //if it is a remote file remote<->http://www.exaple.com, _filename=remote NSString * _filename; NSString * _password; + NSString * _cacheFileName; + NSString * _tmpFileName; BOOL _dirty; id _kdbReader; BOOL _editable; NSMutableDictionary * _remoteFiles; + DBRestClient *_restClient; + + PasswordViewController *_passwordViewController; } @property(nonatomic, retain) id _kdbReader; @property(nonatomic, readonly) BOOL _editable; @property(nonatomic, retain) NSString * _filename; @property(nonatomic, retain) NSString * _password; +@property(nonatomic, retain) NSString * _cacheFileName; +@property(nonatomic, retain) NSString *_tmpFileName; @property(nonatomic, assign) BOOL _dirty; @property(nonatomic, retain) NSMutableDictionary * _remoteFiles; +@property(nonatomic, retain) DBRestClient *_restClient; + +@property(nonatomic, retain) PasswordViewController *_passwordViewController; -(void)getKDBFiles:(NSMutableArray *)list; -(id) readFile:(NSString *) fileName withPassword:(NSString *)password; --(id) readRemoteFile:(NSString *)filename withPassword:(NSString *)password useCached:(BOOL)useCached username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain; +-(id) readRemoteFile:(NSString *)filename withPassword:(NSString *)password useCached:(BOOL)useCached checkUpdate:(BOOL)checkUpdate username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain; -(void)deleteLocalFile:(NSString *)filename; @@ -56,4 +70,9 @@ +(NSString *)getFullFileName:(NSString *)filename; +(NSString *)dataDir; + +-(BOOL)bIsDropBoxFileName:(NSString *)filename; +-(BOOL)bIsDropBoxURL:(NSString *)url; +-(BOOL)bCacheFileExists:(NSString *) filename; +-(BOOL)bCacheFileExitsForURL:(NSString *) url; @end diff --git a/Classes/UI/FileManager.m b/Classes/UI/FileManager.m new file mode 100644 index 0000000..6122de1 --- /dev/null +++ b/Classes/UI/FileManager.m @@ -0,0 +1,396 @@ +// +// FileManager.m +// MyKeePass +// +// Created by Qiang Yu on 3/3/10. +// Copyright 2010 Qiang Yu. All rights reserved. +// + +#import + +//Keepass2 utils +#import + +#import "FileManager.h" +#import "ASIHTTPRequest.h" +#import "MyKeePassAppDelegate.h" +#import "ActivityView.h" +#import "DropboxSDK.h" + +@interface FileManager(PrivateMethods) +-(id) readFileHelp:(NSString *) fileName withPassword:(NSString *)password; +-(id) downLoadFile:(NSString *)url cacheFileName:(NSString *)cacheFileName tmpFileName:(NSString *) tmpFileName withPassword:(NSString *)password username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain; +-(id) checkForUpdate:(NSString *)url cacheFileName:(NSString *)cacheFileName tmpFileName:(NSString *) tmpFileName withPassword:(NSString *)password username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain; +@end + + +@implementation FileManager +@synthesize _kdbReader; +@synthesize _editable; +@synthesize _filename; +@synthesize _password; +@synthesize _dirty; +@synthesize _remoteFiles; +@synthesize _cacheFileName; +@synthesize _restClient; +@synthesize _tmpFileName; + +@synthesize _passwordViewController; + +#define KDB_PATH "Passwords" +#define DOWNLOAD_PATH "Download" + +#define KDB1_SUFFIX ".kdb" +#define KDB2_SUFFIX ".kdbx" + +static NSString * DATA_DIR; +static NSString * DOWNLOAD_DIR; +static NSString * DOWNLOAD_CONFIG; + ++(void)initialize{ + if ( self == [FileManager class] ) { +#if TARGET_IPHONE_SIMULATOR_2 + DATA_DIR = @"/Volumes/Users/qiang/Desktop/"; + DOWNLOAD_DIR = DATA_DIR; +#else + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + DATA_DIR = [[(NSString *)[paths objectAtIndex:0] stringByAppendingPathComponent:@KDB_PATH] retain]; + DOWNLOAD_DIR = [[(NSString *)[paths objectAtIndex:0] stringByAppendingPathComponent:@DOWNLOAD_PATH] retain]; + NSFileManager * fileManager = [NSFileManager defaultManager]; + if(![fileManager fileExistsAtPath:DATA_DIR]){ + [fileManager createDirectoryAtPath:DATA_DIR withIntermediateDirectories:YES attributes:nil error:nil]; + } + if(![fileManager fileExistsAtPath:DOWNLOAD_DIR]){ + [fileManager createDirectoryAtPath:DOWNLOAD_DIR withIntermediateDirectories:YES attributes:nil error:nil]; + } +#endif + DOWNLOAD_CONFIG = [[DOWNLOAD_DIR stringByAppendingPathComponent:@".download"] retain]; + if(![[NSFileManager defaultManager] fileExistsAtPath:DOWNLOAD_CONFIG]){ + NSDictionary * dic = [[NSDictionary alloc]init]; + [dic writeToFile:DOWNLOAD_CONFIG atomically:YES]; + [dic release]; + } + } +} + ++(NSString *)dataDir{ + return DATA_DIR; +} + +-(id)init{ + if(self = [super init]){ + self._remoteFiles = [NSMutableDictionary dictionaryWithContentsOfFile:DOWNLOAD_CONFIG]; + } + return self; +} + +-(void)dealloc{ + [_remoteFiles release]; + [_password release]; + [_filename release]; + [_kdbReader release]; + [_cacheFileName release]; + [_tmpFileName release]; + [super dealloc]; +} + + +-(id) readFile:(NSString *) fileName withPassword:(NSString *)password{ + self._filename = fileName; + return [self readFileHelp:[FileManager getFullFileName:fileName] withPassword:password]; +} + +-(id) readFileHelp:(NSString *) fileName withPassword:(NSString *)password{ + self._password = password; + self._dirty = NO; + + WrapperNSData * source = [[WrapperNSData alloc]initWithContentsOfMappedFile:fileName]; + self._kdbReader = nil; + _kdbReader = [KdbReaderFactory newKdbReader:source]; + // + // only kdb3 file is editable so far + // + _editable = [_kdbReader isKindOfClass:[Kdb3Reader class]]; + [_kdbReader load:source withPassword:password]; + [source release]; + return [_kdbReader getKdbTree]; +} + ++(NSString *)getTempFileNameFromURL:(NSString *)url{ + ByteBuffer * buffer = [Utils createByteBufferForString:url coding:NSUTF8StringEncoding]; + uint8_t hash[20]; + CC_SHA1(buffer._bytes, buffer._size, hash); + [buffer release]; + NSString * filename = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], + hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19], nil]; + + return [DOWNLOAD_DIR stringByAppendingPathComponent:filename]; +} + +-(id) readRemoteFile:(NSString *)filename withPassword:(NSString *)password useCached:(BOOL)useCached checkUpdate:(BOOL)checkUpdate username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain{ + id tree = nil; + self._filename = filename; + + _editable = NO; + NSString * url = [self getURLForRemoteFile:filename]; + + if(!url) @throw [NSException exceptionWithName:@"DownloadError" reason:@"DownloadError" userInfo:nil]; + + NSString * cacheFileName = [FileManager getTempFileNameFromURL:url]; + NSString * tmp = [cacheFileName stringByAppendingString:@".tmp"]; + + self._cacheFileName = cacheFileName; + + NSFileManager * fileManager = [NSFileManager defaultManager]; + + if([fileManager fileExistsAtPath:cacheFileName]&&useCached){ + if (checkUpdate) { + tree = [self checkForUpdate:url cacheFileName:cacheFileName tmpFileName:tmp withPassword:password username:username userpass:userpass domain:domain]; + } + else { + id tree = [self readFileHelp:cacheFileName withPassword:password]; + _editable = NO; + if ([self bIsDropBoxURL:url]) { + [self._passwordViewController performSelector:@selector(fileOperationSuccess) withObject:nil]; + } + return tree; + } + return tree; + } + + tree = [self downLoadFile:url cacheFileName:cacheFileName tmpFileName:tmp withPassword:password username:username userpass:userpass domain:domain]; + + return tree; +} + +-(id) checkForUpdate:(NSString *)url cacheFileName:(NSString *)cacheFileName tmpFileName:(NSString *) tmpFileName withPassword:(NSString *)password username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain { + id tree = nil; + + if (![self bIsDropBoxURL:url]) { + tree = [self downLoadFile:url cacheFileName:cacheFileName tmpFileName:tmpFileName withPassword:password username:username userpass:userpass domain:domain]; + return tree; + } + else { + if (![[DBSession sharedSession] isLinked]) { + @throw [NSException exceptionWithName:@"RemoteAuthenticationError" reason:@"RemoteAuthenticationError" userInfo:nil]; + } + self._password = password; + self._tmpFileName = tmpFileName; + NSString *path = [url substringFromIndex:9]; + [[self _restClient] loadMetadata:path]; + } + return tree; +} + +-(id) downLoadFile:(NSString *)url cacheFileName:(NSString *)cacheFileName tmpFileName:(NSString *) tmpFileName withPassword:(NSString *)password username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain { + id tree = nil; + + if (![self bIsDropBoxURL:url]) { + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]]; + [request setDownloadDestinationPath:tmpFileName]; + + if([username length]) + [request setUsername:username]; + if([userpass length]) + [request setPassword:userpass]; + if([domain length]) + [request setDomain:domain]; + + [request startSynchronous]; + + int statusCode = [request responseStatusCode]; + + if(statusCode!=200){ + if(statusCode==401){ + @throw [NSException exceptionWithName:@"RemoteAuthenticationError" reason:@"RemoteAuthenticationError" userInfo:nil]; + }else{ + @throw [NSException exceptionWithName:@"DownloadError" reason:@"DownloadError" userInfo:nil]; + } + } + + [[NSFileManager defaultManager] removeItemAtPath:cacheFileName error:nil]; + [[NSFileManager defaultManager] moveItemAtPath:tmpFileName toPath:cacheFileName error:nil]; + _passwordViewController._switch.enabled = YES; + _passwordViewController._switch.on = YES; + id tree = [self readFileHelp:cacheFileName withPassword:password]; + return tree; + } + else { + if (![[DBSession sharedSession] isLinked]) { + @throw [NSException exceptionWithName:@"RemoteAuthenticationError" reason:@"RemoteAuthenticationError" userInfo:nil]; + } + self._password = password; + NSString *path = [url substringFromIndex:9]; + [[self _restClient] loadFile:path intoPath:tmpFileName]; + } + return tree; +} + +-(void)getKDBFiles:(NSMutableArray *)list{ + [list removeAllObjects]; + + //kdb/kdbx files + NSFileManager * fileManager = [NSFileManager defaultManager]; + NSArray * contents = [fileManager contentsOfDirectoryAtPath:DATA_DIR error:nil]; + for(NSString * fileName in contents){ + if(![fileName hasPrefix:@"."]){ + [list addObject:fileName]; + } + } + [list sortUsingSelector:@selector(caseInsensitiveCompare:)]; +} + +-(void)getRemoteFiles:(NSMutableArray *)list{ + [list removeAllObjects]; + [list addObjectsFromArray:[_remoteFiles keysSortedByValueUsingSelector:@selector(caseInsensitiveCompare:)]]; + [list sortUsingSelector:@selector(compare:)]; +} + +-(void)addRemoteFile:(NSString *)name Url:(NSString *)url{ + [_remoteFiles setObject:url forKey:name]; + [_remoteFiles writeToFile:DOWNLOAD_CONFIG atomically:YES]; +} + +-(NSString *)getURLForRemoteFile:(NSString *)name{ + return [_remoteFiles objectForKey:name]; +} + +-(void)deleteLocalFile:(NSString *)filename{ + [[NSFileManager defaultManager] removeItemAtPath:[FileManager getFullFileName:filename] error:nil]; +} + +-(void)deleteRemoteFile:(NSString *)name{ + [_remoteFiles removeObjectForKey:name]; + [_remoteFiles writeToFile:DOWNLOAD_CONFIG atomically:YES]; +} + +-(NSUInteger) getKDBVersion{ + if([_kdbReader isKindOfClass:[Kdb3Reader class]]){ + return KDB_VERSION1; + }else{ + return KDB_VERSION2; + } +} + +-(void)save{ + if(!_dirty) return; + if([_kdbReader isKindOfClass:[Kdb3Reader class]]){ + Kdb3Writer * writer = nil; + @try{ + writer = [[Kdb3Writer alloc]init]; + [writer persist:[_kdbReader getKdbTree] file:[FileManager getFullFileName:_filename] withPassword:_password]; + _dirty = NO; + }@finally { + [writer release]; + } + } +} + ++(NSString *)getFullFileName:(NSString *)filename{ + return [DATA_DIR stringByAppendingPathComponent:filename]; +} + ++(void)newKdb3File:(NSString *)filename withPassword:(NSString *)password{ + Kdb3Writer * writer = nil; + @try{ + writer = [[Kdb3Writer alloc]init]; + [writer newFile:[FileManager getFullFileName:filename] withPassword:password]; + }@finally { + [writer release]; + } +} + +-(BOOL)bIsDropBoxFileName:(NSString *)filename { + NSString *url = [self getURLForRemoteFile:filename]; + return [self bIsDropBoxURL:url]; +} + +-(BOOL)bIsDropBoxURL:(NSString *) url { + if ([url hasPrefix:@"dropbox://"]){ + return YES; + } + return NO; +} + +-(BOOL)bCacheFileExists:(NSString *) filename { + NSString *url = [self getURLForRemoteFile:filename]; + return [self bCacheFileExitsForURL:url]; +} + +-(BOOL)bCacheFileExitsForURL:(NSString *) url { + NSString * cacheFileName = [FileManager getTempFileNameFromURL:url]; + + NSFileManager * fileManager = [NSFileManager defaultManager]; + + if([fileManager fileExistsAtPath:cacheFileName]) { + return YES; + } + return NO; +} + +#pragma mark DBRestClient + +- (DBRestClient*)_restClient { + if (!_restClient) { + _restClient = + [[DBRestClient alloc] initWithSession:[DBSession sharedSession]]; + _restClient.delegate = self; + } + return _restClient; +} + +#pragma mark DBRestClientDelegate methods + +-(void)restClient:(DBRestClient*)client loadedMetadata:(DBMetadata*)metadata { + NSFileManager * fileManager = [NSFileManager defaultManager]; + NSDictionary *fileAttributes; + NSError *errorFile = nil; + + fileAttributes = [fileManager attributesOfItemAtPath:_cacheFileName error:&errorFile]; + if (errorFile == nil) { + NSDate * localFileDate = [fileAttributes objectForKey:NSFileModificationDate]; + if ([[[metadata lastModifiedDate] laterDate:localFileDate] isEqual:localFileDate]) { + @try{ + id tree = [self readFileHelp:self._cacheFileName withPassword:self._password]; + [self._passwordViewController performSelector:@selector(fileOperationSuccess) withObject:nil]; + }@catch(NSException * exception){ + [self._passwordViewController performSelector:@selector(fileOperationFailureWithException:) withObject:exception]; + } + return; + } + } + [[self _restClient] loadFile:metadata.path intoPath:_tmpFileName]; +} + +-(void)restClient:(DBRestClient*)client metadataUnchangedAtPath:(NSString*)path { + // NSLog(@"Metadata unchanged!"); +} + +-(void)restClient:(DBRestClient*)client loadMetadataFailedWithError:(NSError*)error { + NSException *exception = [NSException exceptionWithName:@"MetadataErrorWithUserInfo" reason:@"DownloadError" userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[error localizedDescription],@"error", nil]]; + [self._passwordViewController performSelector:@selector(fileOperationFailureWithException:) withObject:exception]; +} + +-(void)restClient:(DBRestClient*)client loadedFile:(NSString*)destPath{ + [[NSFileManager defaultManager] removeItemAtPath:self._cacheFileName error:nil]; + [[NSFileManager defaultManager] moveItemAtPath:destPath toPath:self._cacheFileName error:nil]; + @try{ + id tree = [self readFileHelp:self._cacheFileName withPassword:self._password]; + tree = nil; + [self._passwordViewController performSelector:@selector(fileOperationSuccess) withObject:nil]; + }@catch(NSException * exception){ + [self._passwordViewController performSelector:@selector(fileOperationFailureWithException:) withObject:exception]; + } +} + +-(void)restClient:(DBRestClient*)client loadProgress:(CGFloat)progress forFile:(NSString*)destPath { + //NSLog(@"Progress"); +} + +-(void)restClient:(DBRestClient*)client loadFileFailedWithError:(NSError*)error { + NSException *exception = [NSException exceptionWithName:@"DownloadErrorWithUserInfo" reason:@"DownloadError" userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[error localizedDescription],@"error", nil]]; + [self._passwordViewController performSelector:@selector(fileOperationFailureWithException:) withObject:exception]; +} + +@end diff --git a/GroupedSectionHeader.h b/Classes/UI/GroupedSectionHeader.h similarity index 100% rename from GroupedSectionHeader.h rename to Classes/UI/GroupedSectionHeader.h diff --git a/GroupedSectionHeader.m b/Classes/UI/GroupedSectionHeader.m similarity index 100% rename from GroupedSectionHeader.m rename to Classes/UI/GroupedSectionHeader.m diff --git a/EditNodeNameViewController.h b/Classes/UI/Kdb/EditNodeNameViewController.h similarity index 100% rename from EditNodeNameViewController.h rename to Classes/UI/Kdb/EditNodeNameViewController.h diff --git a/EditNodeNameViewController.m b/Classes/UI/Kdb/EditNodeNameViewController.m similarity index 100% rename from EditNodeNameViewController.m rename to Classes/UI/Kdb/EditNodeNameViewController.m diff --git a/EditNodeViewController.h b/Classes/UI/Kdb/EditNodeViewController.h similarity index 100% rename from EditNodeViewController.h rename to Classes/UI/Kdb/EditNodeViewController.h diff --git a/EditNodeViewController.m b/Classes/UI/Kdb/EditNodeViewController.m similarity index 100% rename from EditNodeViewController.m rename to Classes/UI/Kdb/EditNodeViewController.m diff --git a/EntrySearchViewController.h b/Classes/UI/Kdb/EntrySearchViewController.h similarity index 100% rename from EntrySearchViewController.h rename to Classes/UI/Kdb/EntrySearchViewController.h diff --git a/EntrySearchViewController.m b/Classes/UI/Kdb/EntrySearchViewController.m similarity index 100% rename from EntrySearchViewController.m rename to Classes/UI/Kdb/EntrySearchViewController.m diff --git a/EntryViewController.h b/Classes/UI/Kdb/EntryViewController.h similarity index 100% rename from EntryViewController.h rename to Classes/UI/Kdb/EntryViewController.h diff --git a/EntryViewController.m b/Classes/UI/Kdb/EntryViewController.m similarity index 100% rename from EntryViewController.m rename to Classes/UI/Kdb/EntryViewController.m diff --git a/GroupViewController.h b/Classes/UI/Kdb/GroupViewController.h similarity index 100% rename from GroupViewController.h rename to Classes/UI/Kdb/GroupViewController.h diff --git a/GroupViewController.m b/Classes/UI/Kdb/GroupViewController.m similarity index 100% rename from GroupViewController.m rename to Classes/UI/Kdb/GroupViewController.m diff --git a/KdbViewController.h b/Classes/UI/Kdb/KdbViewController.h similarity index 100% rename from KdbViewController.h rename to Classes/UI/Kdb/KdbViewController.h diff --git a/KdbViewController.m b/Classes/UI/Kdb/KdbViewController.m similarity index 100% rename from KdbViewController.m rename to Classes/UI/Kdb/KdbViewController.m diff --git a/NewEntryViewController.h b/Classes/UI/Kdb/NewEntryViewController.h similarity index 100% rename from NewEntryViewController.h rename to Classes/UI/Kdb/NewEntryViewController.h diff --git a/NewEntryViewController.m b/Classes/UI/Kdb/NewEntryViewController.m similarity index 100% rename from NewEntryViewController.m rename to Classes/UI/Kdb/NewEntryViewController.m diff --git a/NewGroupViewController.h b/Classes/UI/Kdb/NewGroupViewController.h similarity index 100% rename from NewGroupViewController.h rename to Classes/UI/Kdb/NewGroupViewController.h diff --git a/NewGroupViewController.m b/Classes/UI/Kdb/NewGroupViewController.m similarity index 100% rename from NewGroupViewController.m rename to Classes/UI/Kdb/NewGroupViewController.m diff --git a/OptionViewController.h b/Classes/UI/Kdb/OptionViewController.h similarity index 100% rename from OptionViewController.h rename to Classes/UI/Kdb/OptionViewController.h diff --git a/OptionViewController.m b/Classes/UI/Kdb/OptionViewController.m similarity index 100% rename from OptionViewController.m rename to Classes/UI/Kdb/OptionViewController.m diff --git a/PasswordDisclosureView.h b/Classes/UI/Kdb/PasswordDisclosureView.h similarity index 100% rename from PasswordDisclosureView.h rename to Classes/UI/Kdb/PasswordDisclosureView.h diff --git a/PasswordDisclosureView.m b/Classes/UI/Kdb/PasswordDisclosureView.m similarity index 100% rename from PasswordDisclosureView.m rename to Classes/UI/Kdb/PasswordDisclosureView.m diff --git a/Sort.h b/Classes/UI/Kdb/Sort.h similarity index 100% rename from Sort.h rename to Classes/UI/Kdb/Sort.h diff --git a/Sort.m b/Classes/UI/Kdb/Sort.m similarity index 100% rename from Sort.m rename to Classes/UI/Kdb/Sort.m diff --git a/Classes/UI/Main/DropboxFileViewController.h b/Classes/UI/Main/DropboxFileViewController.h new file mode 100644 index 0000000..8cf906b --- /dev/null +++ b/Classes/UI/Main/DropboxFileViewController.h @@ -0,0 +1,31 @@ +// +// DropboxFileViewController.h +// MyKeePass +// +// Created by Jose Ramon Roca on 07/05/11. +// Copyright 2011 -. All rights reserved. +// + +#import +#import "DropboxSDK.h" + +@class DBRestClient; + +@interface DropboxFileViewController : UIViewController { + UITableView *tableView; + DBRestClient *restClient; + NSMutableArray *dropBoxContents; + UIActivityIndicatorView* activityIndicator; + BOOL working; + NSString *currentPath; + DropboxFileViewController *dropboxFileSubViewController; +} + +@property (nonatomic, retain) IBOutlet UITableView *tableView; +@property (nonatomic, retain) DBRestClient *restClient; +@property (nonatomic, retain) NSMutableArray *dropBoxContents; +@property (nonatomic, retain) IBOutlet UIActivityIndicatorView* activityIndicator; +@property (nonatomic, retain) NSString *currentPath; +@property (nonatomic, retain) DropboxFileViewController *dropboxFileSubViewController; + +@end diff --git a/Classes/UI/Main/DropboxFileViewController.m b/Classes/UI/Main/DropboxFileViewController.m new file mode 100644 index 0000000..29410c1 --- /dev/null +++ b/Classes/UI/Main/DropboxFileViewController.m @@ -0,0 +1,329 @@ +// +// DropboxFileViewController.m +// MyKeePass +// +// Created by Jose Ramon Roca on 07/05/11. +// Copyright 2011 -. All rights reserved. +// + +#import "DropboxFileViewController.h" +#import "DropboxSDK.h" +#import "FileViewController.h" +#import "MyKeePassAppDelegate.h" + +@interface DropboxFileViewController(PrivateMethods) +-(IBAction)cancelClicked:(id)sender; +-(void)updateTable; +- (void)setWorking:(BOOL)isWorking; +-(void)configureCell:(UITableViewCell*) cell indexPath:(NSIndexPath *)indexPath; +@end + + +@implementation DropboxFileViewController + +#define TYPE_DIR "D" +#define TYPE_FILE "F" + +#define DROPBOX_ARRAY_TYPE 0 +#define DROPBOX_ARRAY_PATH 1 + +@synthesize tableView; +@synthesize restClient; +@synthesize dropBoxContents; +@synthesize activityIndicator; +@synthesize currentPath; +@synthesize dropboxFileSubViewController; + +- (void)dealloc +{ + [restClient release]; + [dropBoxContents release]; + [activityIndicator release]; + [currentPath release]; + [dropboxFileSubViewController release]; + [super dealloc]; +} + +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + //DBLoginController* controller = [[DBLoginController new] autorelease]; + //[controller presentFromController:self]; + + // Uncomment the following line to preserve selection between presentations. + // self.clearsSelectionOnViewWillAppear = NO; + + // Uncomment the following line to display an Edit button in the navigation bar for this view controller. + // self.navigationItem.rightBarButtonItem = self.editButtonItem; + self.navigationItem.title = NSLocalizedString(@"New Dropbox File", @"New Dropbox File"); + + UIBarButtonItem * cancel = [[UIBarButtonItem alloc]initWithTitle:NSLocalizedString(@"Cancel", @"Cancel") + style:UIBarButtonItemStylePlain target:self action:@selector(cancelClicked:)]; + self.navigationItem.rightBarButtonItem = cancel; + [cancel release]; + + /* + UIBarButtonItem * done = [[UIBarButtonItem alloc]initWithTitle:NSLocalizedString(@"Done", @"Done") + style:UIBarButtonItemStyleDone target:self action:@selector(doneClicked:)]; + self.navigationItem.rightBarButtonItem = done; + [done release]; + */ + dropBoxContents = [NSMutableArray new]; + if (currentPath == nil) { + currentPath = @"/"; + } +} + +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + if (![[DBSession sharedSession] isLinked]) { + DBLoginController* controller = [[DBLoginController new] autorelease]; + controller.delegate = self; + [controller presentFromController:self]; + } + else + { + [self updateTable]; + } +} + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + // Return YES for supported orientations + return (interfaceOrientation == UIInterfaceOrientationPortrait); +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + // Return the number of sections. + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + // Return the number of rows in the section. + return [dropBoxContents count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + + UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; + } + + // Configure the cell... + [self configureCell:cell indexPath:indexPath]; + return cell; +} + +/* +// Override to support conditional editing of the table view. +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath +{ + // Return NO if you do not want the specified item to be editable. + return YES; +} +*/ + +/* +// Override to support editing the table view. +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (editingStyle == UITableViewCellEditingStyleDelete) { + // Delete the row from the data source + [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; + } + else if (editingStyle == UITableViewCellEditingStyleInsert) { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view + } +} +*/ + +/* +// Override to support rearranging the table view. +- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath +{ +} +*/ + +/* +// Override to support conditional rearranging of the table view. +- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath +{ + // Return NO if you do not want the item to be re-orderable. + return YES; +} +*/ + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + + NSMutableArray *aAux = [dropBoxContents objectAtIndex:indexPath.row]; + if ([[aAux objectAtIndex:DROPBOX_ARRAY_TYPE] isEqualToString:@"D"]) { + if (dropboxFileSubViewController == nil) { + DropboxFileViewController *dropBoxViewController = [[DropboxFileViewController alloc] initWithNibName:@"DropboxFileView" bundle:nil]; + self.dropboxFileSubViewController = dropBoxViewController; + [dropBoxViewController release]; + } + dropboxFileSubViewController.currentPath = [aAux objectAtIndex:DROPBOX_ARRAY_PATH]; + [[self navigationController] pushViewController:self.dropboxFileSubViewController animated:YES]; + } + else { + NSString *path = [aAux objectAtIndex:DROPBOX_ARRAY_PATH]; + NSString *url = [NSString stringWithFormat:@"dropbox://%@", [path substringWithRange:NSMakeRange(1, [path length]-1)]]; + NSString *name = [[aAux objectAtIndex:DROPBOX_ARRAY_PATH] lastPathComponent]; + if([[MyKeePassAppDelegate delegate]._fileManager getURLForRemoteFile:name]) { + UIAlertView * alert = [[UIAlertView alloc]initWithTitle:nil + message:NSLocalizedString(@"A same name already exists", @"Name already exisits") delegate:nil + cancelButtonTitle:NSLocalizedString(@"OK", @"OK") + otherButtonTitles:nil]; + [alert show]; + [alert release]; + } + else { + [[MyKeePassAppDelegate delegate]._fileManager addRemoteFile:name Url:url]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissModalViewOK" object:self]; + } + } +} + +#pragma mark DBLoginControllerDelegate methods + +- (void)loginControllerDidLogin:(DBLoginController*)controller { + [self updateTable]; +} + +- (void)loginControllerDidCancel:(DBLoginController*)controller { + [self cancelClicked:nil]; +} + +#pragma mark DBRestClient + +- (DBRestClient*)restClient { + if (!restClient) { + restClient = + [[DBRestClient alloc] initWithSession:[DBSession sharedSession]]; + restClient.delegate = self; + } + return restClient; +} + + +#pragma mark DBRestClientDelegate methods + +- (void)restClient:(DBRestClient*)client loadedMetadata:(DBMetadata*)metadata { + + NSArray *validExtensions = [NSArray arrayWithObjects:@"kdb", @"kdbx", nil]; + NSMutableArray *aAux; + [dropBoxContents release]; + dropBoxContents = [NSMutableArray new]; + + for (DBMetadata *child in metadata.contents) { + if (child.isDirectory) { + aAux = [[NSMutableArray alloc] init]; + [aAux autorelease]; + [aAux insertObject:@"D" atIndex:DROPBOX_ARRAY_TYPE]; + [aAux insertObject:child.path atIndex:DROPBOX_ARRAY_PATH]; + [dropBoxContents addObject:aAux]; + } + else { + NSString* extension = [[child.path pathExtension] lowercaseString]; + if ([validExtensions indexOfObject:extension] != NSNotFound) { + aAux = [[NSMutableArray alloc] init]; + [aAux autorelease]; + [aAux insertObject:@"F" atIndex:DROPBOX_ARRAY_TYPE]; + [aAux insertObject:child.path atIndex:DROPBOX_ARRAY_PATH]; + [dropBoxContents addObject:aAux]; + } + } + } + [self setWorking:NO]; + [[self tableView] reloadData]; +} + +- (void)restClient:(DBRestClient*)client metadataUnchangedAtPath:(NSString*)path { + + NSLog(@"Metadata unchanged!"); +} + +- (void)restClient:(DBRestClient*)client loadMetadataFailedWithError:(NSError*)error { +#warning Need to handle errors. + NSLog(@"Error loading metadata: %@", error); +} + +#pragma mark - Private Methods + +-(IBAction)cancelClicked:(id)sender{ + [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissModalViewCancel" object:self]; +} + +-(void)updateTable { + [self setWorking:YES]; + [[self restClient] loadMetadata:currentPath]; +} + +-(void)setWorking:(BOOL)isWorking { + if (working == isWorking) return; + working = isWorking; + + if (working) { + [activityIndicator startAnimating]; + } else { + [activityIndicator stopAnimating]; + } +} + +-(void)configureCell:(UITableViewCell*) cell indexPath:(NSIndexPath *)indexPath { + NSMutableArray *aAux = [dropBoxContents objectAtIndex:indexPath.row]; + + cell.textLabel.text = [[aAux objectAtIndex:DROPBOX_ARRAY_PATH] lastPathComponent]; + if ([[aAux objectAtIndex:DROPBOX_ARRAY_TYPE] isEqualToString:@"D"]) { + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + } + else { + cell.accessoryType = UITableViewCellAccessoryCheckmark; + } +} + +@end diff --git a/FileManagerOperation.h b/Classes/UI/Main/FileManagerOperation.h similarity index 91% rename from FileManagerOperation.h rename to Classes/UI/Main/FileManagerOperation.h index 2141a82..bd9b265 100644 --- a/FileManagerOperation.h +++ b/Classes/UI/Main/FileManagerOperation.h @@ -27,6 +27,7 @@ NSString * _domain; BOOL _useCache; + BOOL _checkUpdate; } @property(nonatomic, retain) NSObject * _delegate; @@ -36,11 +37,14 @@ @property(nonatomic, retain) NSString * _userpass; @property(nonatomic, retain) NSString * _domain; @property(nonatomic, assign) BOOL _useCache; +@property(nonatomic, assign) BOOL _checkUpdate; + -(id)initWithDelegate:(id)delegate; -(void)openLocalFile; -(void)openRemoteFile; +-(void)openDropboxRemoteFile; -(void)save; @end diff --git a/FileManagerOperation.m b/Classes/UI/Main/FileManagerOperation.m similarity index 72% rename from FileManagerOperation.m rename to Classes/UI/Main/FileManagerOperation.m index 7ee4b89..a55924b 100644 --- a/FileManagerOperation.m +++ b/Classes/UI/Main/FileManagerOperation.m @@ -18,6 +18,7 @@ @implementation FileManagerOperation @synthesize _userpass; @synthesize _domain; @synthesize _useCache; +@synthesize _checkUpdate; @synthesize _delegate; -(id)initWithDelegate:(id)delegate{ @@ -54,8 +55,8 @@ -(void)openLocalFile{ -(void)openRemoteFile{ NSAutoreleasePool * pool = nil; @try{ - pool = [[NSAutoreleasePool alloc] init]; - [[MyKeePassAppDelegate delegate]._fileManager readRemoteFile:_filename withPassword:_password useCached:_useCache username:_username userpass:_userpass domain:_domain]; + pool = [[NSAutoreleasePool alloc] init]; + [[MyKeePassAppDelegate delegate]._fileManager readRemoteFile:_filename withPassword:_password useCached:_useCache checkUpdate:_checkUpdate username:_username userpass:_userpass domain:_domain]; [_delegate performSelectorOnMainThread:@selector(fileOperationSuccess) withObject:nil waitUntilDone:NO]; }@catch(NSException * exception){ [_delegate performSelectorOnMainThread:@selector(fileOperationFailureWithException:) withObject:exception waitUntilDone:NO]; @@ -66,6 +67,16 @@ -(void)openRemoteFile{ } +-(void)openDropboxRemoteFile{ + @try{ + [MyKeePassAppDelegate delegate]._fileManager._passwordViewController = self._delegate; + [[MyKeePassAppDelegate delegate]._fileManager readRemoteFile:_filename withPassword:_password useCached:_useCache checkUpdate:_checkUpdate username:_username userpass:_userpass domain:_domain]; + //[_delegate performSelectorOnMainThread:@selector(fileOperationSuccess) withObject:nil waitUntilDone:NO]; + }@catch(NSException * exception){ + [_delegate performSelectorOnMainThread:@selector(fileOperationFailureWithException:) withObject:exception waitUntilDone:NO]; + } +} + -(void)save{ NSAutoreleasePool * pool = nil; @try{ diff --git a/FileUploadViewController.h b/Classes/UI/Main/FileUploadViewController.h similarity index 100% rename from FileUploadViewController.h rename to Classes/UI/Main/FileUploadViewController.h diff --git a/FileUploadViewController.m b/Classes/UI/Main/FileUploadViewController.m similarity index 100% rename from FileUploadViewController.m rename to Classes/UI/Main/FileUploadViewController.m diff --git a/FileViewController.h b/Classes/UI/Main/FileViewController.h similarity index 100% rename from FileViewController.h rename to Classes/UI/Main/FileViewController.h diff --git a/FileViewController.m b/Classes/UI/Main/FileViewController.m similarity index 81% rename from FileViewController.m rename to Classes/UI/Main/FileViewController.m index a3ea3f5..d6fd4ed 100644 --- a/FileViewController.m +++ b/Classes/UI/Main/FileViewController.m @@ -16,6 +16,8 @@ #import "RenameFileViewController.h" #import "RenameRemoteFileViewController.h" #import "FileUploadViewController.h" +#import "DropboxSDK.h" +#import "DropboxFileViewController.h" #define KDB1_SUFFIX ".kdb" #define KDB2_SUFFIX ".kdbx" @@ -23,10 +25,12 @@ #define NEW_FILE_BUTTON 0 #define IMPORT_DESKTOP_BUTTON 1 #define IMPORT_WEBSERVER_BUTTON 2 +#define IMPORT_DROPBOX_BUTTON 3 @interface FileViewController(PrivateMethods) -(void)newFile; -(void)downloadFile; +-(void)dropboxFile; -(void)uploadFile; @end @@ -78,14 +82,18 @@ - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexP [nav release]; }else{ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissModalViewCancel:) name:@"DismissModalViewCancel" object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissModalViewOK:) name:@"DismissModalViewOK" object:nil]; - RenameRemoteFileViewController * renameFile = [[RenameRemoteFileViewController alloc]initWithStyle:UITableViewStyleGrouped]; - renameFile._name = [_remoteFiles objectAtIndex:indexPath.row - [_files count]]; - renameFile._url = [[MyKeePassAppDelegate delegate]._fileManager getURLForRemoteFile:renameFile._name]; - UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:renameFile]; - [self presentModalViewController:nav animated:YES]; - [renameFile release]; - [nav release]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissModalViewOK:) name:@"DismissModalViewOK" object:nil]; + + NSString *filename = [_remoteFiles objectAtIndex:indexPath.row - [_files count]]; + if (![[MyKeePassAppDelegate delegate]._fileManager bIsDropBoxFileName:filename]) { + RenameRemoteFileViewController * renameFile = [[RenameRemoteFileViewController alloc]initWithStyle:UITableViewStyleGrouped]; + renameFile._name = [_remoteFiles objectAtIndex:indexPath.row - [_files count]]; + renameFile._url = [[MyKeePassAppDelegate delegate]._fileManager getURLForRemoteFile:renameFile._name]; + UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:renameFile]; + [self presentModalViewController:nav animated:YES]; + [renameFile release]; + [nav release]; + } } } @@ -118,7 +126,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N //cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; NSString * filename = [_remoteFiles objectAtIndex:indexPath.row-[_files count]]; UIImageView * iv = cell.imageView; - iv.image = [UIImage imageNamed:@"http.png"]; + if ([[MyKeePassAppDelegate delegate]._fileManager bIsDropBoxFileName:filename]) { + iv.image = [UIImage imageNamed:@"dropbox.png"]; + cell.editingAccessoryType =UITableViewCellEditingStyleNone; + } + else { + iv.image = [UIImage imageNamed:@"http.png"]; + } cell.textLabel.text = filename; } return cell; @@ -184,6 +198,16 @@ -(void)downloadFile{ [nav release]; } +-(void)dropboxFile{ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissModalViewCancel:) name:@"DismissModalViewCancel" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissModalViewOK:) name:@"DismissModalViewOK" object:nil]; + DropboxFileViewController *aDropboxFileViewController = [[DropboxFileViewController alloc]initWithNibName:@"DropboxFileView" bundle:nil]; + UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:aDropboxFileViewController]; + [self presentModalViewController:nav animated:YES]; + [aDropboxFileViewController release]; + [nav release]; +} + -(void)dismissModalViewCancel:(NSNotification *)notification{ [self dismissModalViewControllerAnimated:YES]; [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -210,6 +234,9 @@ -(void)dismissModalViewOK:(NSNotification *)notification{ }else if([[notification object] isKindOfClass:[FileUploadViewController class]]){ [[MyKeePassAppDelegate delegate]._fileManager getKDBFiles:_files]; [self.tableView reloadData]; + }else if ([[notification object] isKindOfClass:[DropboxFileViewController class]]){ + [[MyKeePassAppDelegate delegate]._fileManager getRemoteFiles:_remoteFiles]; + [self.tableView reloadData]; } [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -220,7 +247,8 @@ -(IBAction)addFile:(id)sender { cancelButtonTitle:NSLocalizedString(@"Cancel", @"Cancel") destructiveButtonTitle:nil otherButtonTitles:NSLocalizedString(@"New KDB 1.0 File", @"New KDB 1.0 File"), NSLocalizedString(@"Upload From Desktop", @"Upload From Desktop"), - NSLocalizedString(@"Download From WWW", @"Download From WWW"), nil]; + NSLocalizedString(@"Download From WWW", @"Download From WWW"), + NSLocalizedString(@"Download From Dropbox", @"Download From Dropbox"), nil]; [as showInView:[MyKeePassAppDelegate getWindow]]; } @@ -238,6 +266,10 @@ - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger [self downloadFile]; break; } + case IMPORT_DROPBOX_BUTTON:{ + [self dropboxFile]; + break; + } } } diff --git a/MainViewController.h b/Classes/UI/Main/MainViewController.h similarity index 100% rename from MainViewController.h rename to Classes/UI/Main/MainViewController.h diff --git a/MainViewController.m b/Classes/UI/Main/MainViewController.m similarity index 100% rename from MainViewController.m rename to Classes/UI/Main/MainViewController.m diff --git a/NewLocalFileViewController.h b/Classes/UI/Main/NewLocalFileViewController.h similarity index 100% rename from NewLocalFileViewController.h rename to Classes/UI/Main/NewLocalFileViewController.h diff --git a/NewLocalFileViewController.m b/Classes/UI/Main/NewLocalFileViewController.m similarity index 100% rename from NewLocalFileViewController.m rename to Classes/UI/Main/NewLocalFileViewController.m diff --git a/NewRemoteFileViewController.h b/Classes/UI/Main/NewRemoteFileViewController.h similarity index 100% rename from NewRemoteFileViewController.h rename to Classes/UI/Main/NewRemoteFileViewController.h diff --git a/NewRemoteFileViewController.m b/Classes/UI/Main/NewRemoteFileViewController.m similarity index 100% rename from NewRemoteFileViewController.m rename to Classes/UI/Main/NewRemoteFileViewController.m diff --git a/PasswordViewController.h b/Classes/UI/Main/PasswordViewController.h similarity index 87% rename from PasswordViewController.h rename to Classes/UI/Main/PasswordViewController.h index e676a13..6e693c3 100644 --- a/PasswordViewController.h +++ b/Classes/UI/Main/PasswordViewController.h @@ -22,9 +22,11 @@ ActivityView * _av; UIButton * _ok; UIButton * _cancel; - UISwitch * _switch; + UISwitch * _switch; + UISwitch * _switchCheckUpdate; TextFieldCell * _password; UITableViewCell * _useCache; + UITableViewCell *_checkUpdate; TextFieldCell * _rusername; TextFieldCell * _rpassword; TextFieldCell * _rdomain; @@ -38,9 +40,11 @@ @property(nonatomic, retain) UIButton * _ok; @property(nonatomic, retain) UIButton * _cancel; @property(nonatomic, retain) UISwitch * _switch; +@property(nonatomic, retain) UISwitch * _switchCheckUpdate; @property(nonatomic, retain) TextFieldCell * _password; @property(nonatomic, retain) UITableViewCell * _useCache; +@property(nonatomic, retain) UITableViewCell * _checkUpdate; @property(nonatomic, retain) TextFieldCell * _rusername; @property(nonatomic, retain) TextFieldCell * _rpassword; @property(nonatomic, retain) TextFieldCell * _rdomain; diff --git a/PasswordViewController.m b/Classes/UI/Main/PasswordViewController.m similarity index 71% rename from PasswordViewController.m rename to Classes/UI/Main/PasswordViewController.m index 52622b7..5c797c9 100644 --- a/PasswordViewController.m +++ b/Classes/UI/Main/PasswordViewController.m @@ -11,6 +11,7 @@ #import "MyKeePassAppDelegate.h" #import "ActivityView.h" #import "FileManagerOperation.h" +#import "FileManager.h" @interface PasswordViewController(PrivateMethods) -(void)showError:(NSString *)message; @@ -24,9 +25,11 @@ @implementation PasswordViewController @synthesize _ok; @synthesize _cancel; @synthesize _switch; +@synthesize _switchCheckUpdate; @synthesize _av; @synthesize _password; @synthesize _useCache; +@synthesize _checkUpdate; @synthesize _rusername; @synthesize _rpassword; @synthesize _rdomain; @@ -49,6 +52,7 @@ - (void)dealloc { [_av release]; [_password release]; [_switch release]; + [_switchCheckUpdate release]; [_useCache release]; [_rusername release]; [_rpassword release]; @@ -92,10 +96,28 @@ -(void)viewDidLoad{ _useCache.textLabel.textColor = [UIColor darkGrayColor]; _useCache.selectionStyle = UITableViewCellSelectionStyleNone; + _checkUpdate = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + _checkUpdate.textLabel.text = NSLocalizedString(@"Check for update", @"Check for update"); + _checkUpdate.textLabel.font = [UIFont systemFontOfSize:17]; + _checkUpdate.textLabel.textColor = [UIColor darkGrayColor]; + _checkUpdate.selectionStyle = UITableViewCellSelectionStyleNone; + _switch = [[UISwitch alloc]initWithFrame:CGRectMake(195, 6, 94, 27)]; - _switch.on = YES; + [_switch addTarget:self action:@selector(useCacheChanged:) forControlEvents:UIControlEventValueChanged]; + + _switch.on = YES; + + _switchCheckUpdate = [[UISwitch alloc]initWithFrame:CGRectMake(195, 6, 94, 27)]; + _switchCheckUpdate.on = NO; + + if (![[MyKeePassAppDelegate delegate]._fileManager bCacheFileExists:_filename]) { + _switch.on = NO; + _switch.enabled = NO; + _switchCheckUpdate.enabled = NO; + } - [_useCache.contentView addSubview:_switch]; + [_useCache.contentView addSubview:_switch]; + [_checkUpdate.contentView addSubview:_switchCheckUpdate]; //set the footer; UIView * container = [[UIView alloc]initWithFrame:CGRectMake(0,0,320,44)]; @@ -136,14 +158,35 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return _isRemote?2:1; + if (!_isRemote) { + return 1; + } + else { + if ([[MyKeePassAppDelegate delegate]._fileManager bIsDropBoxFileName:_filename]){ + return 1; + } + else { + return 2; + } + } + return 1; } // Customize the number of rows in the table view. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if(section==0){ - return _isRemote?2:1; + if (!_isRemote) { + return 1; + } + else { + if ([[MyKeePassAppDelegate delegate]._fileManager bIsDropBoxFileName:_filename]){ + return 3; + } + else { + return 2; + } + } }else{ return 3; } @@ -152,10 +195,18 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger // Customize the appearance of table view cells. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if([indexPath section]==0){ - if([indexPath row]==0) - return _password; - else - return _useCache; + switch ([indexPath row]) { + case 0: + return _password; + break; + case 1: + return _useCache; + break; + case 2: + return _checkUpdate; + default: + break; + } }else{ switch ([indexPath row]) { case 0: @@ -186,15 +237,22 @@ -(IBAction)okClicked:(id)sender{ [self.view addSubview:_av]; if(!_op) _op = [[FileManagerOperation alloc]initWithDelegate:self]; _op._filename = _filename; - _op._password = _password._field.text; + _op._password = _password._field.text; + if(!self._isRemote){ [_op performSelectorInBackground:@selector(openLocalFile) withObject:nil]; }else{ _op._useCache = _switch.on; + _op._checkUpdate = _switchCheckUpdate.on; _op._username = _rusername._field.text; _op._userpass = _rpassword._field.text; - _op._domain = _rdomain._field.text; - [_op performSelectorInBackground:@selector(openRemoteFile) withObject:nil]; + _op._domain = _rdomain._field.text; + if (![[MyKeePassAppDelegate delegate]._fileManager bIsDropBoxFileName:_filename]) { + [_op performSelectorInBackground:@selector(openRemoteFile) withObject:nil]; + } + else { + [_op openDropboxRemoteFile]; + } } }else{ // it is reopen, we verify the password directly NSString * password = _password._field.text; @@ -207,6 +265,8 @@ -(IBAction)okClicked:(id)sender{ } -(void)fileOperationSuccess{ + _switch.enabled = YES; + _switch.on = YES; [_av removeFromSuperview]; [[NSNotificationCenter defaultCenter] postNotificationName:@"DismissModalViewOK" object:self]; } @@ -215,6 +275,8 @@ -(void)fileOperationFailureWithException:(NSException *)exception{ [_av removeFromSuperview]; _ok.enabled = _cancel.enabled = YES; _isLoading = NO; + _switch.enabled = YES; + _switch.on = YES; if([[exception name] isEqualToString:@"DecryptError"]){ [self showError:NSLocalizedString(@"Master password is not correct", @"Master password is not correct")]; @@ -224,6 +286,10 @@ -(void)fileOperationFailureWithException:(NSException *)exception{ [msg release]; }else if([[exception name] isEqualToString:@"DownloadError"]){ [self showError:NSLocalizedString(@"Cannot download the file", @"Cannot download the file")]; + }else if([[exception name] isEqualToString:@"MetadataErrorWithUserInfo"]){ + [self showError:NSLocalizedString(@"Cannot download the file", @"Cannot download the file")]; + }else if([[exception name] isEqualToString:@"DownloadErrorWithUserInfo"]){ + [self showError:[NSString stringWithFormat:@"%@.%@", NSLocalizedString(@"Cannot download the file", @"Cannot download the file"),[[exception userInfo] valueForKey:@"error"]]]; }else if ([[exception name] isEqualToString:@"RemoteAuthenticationError"]){ [self showError:NSLocalizedString(@"Server authentication error", @"Server authentication error")]; }else{ @@ -247,5 +313,15 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField{ return NO; } +-(void)useCacheChanged:(UISwitch *)sender { + if (!sender.on) { + _switchCheckUpdate.on = NO; + _switchCheckUpdate.enabled = NO; + } + else { + _switchCheckUpdate.enabled = YES; + } +} + @end diff --git a/RenameFileViewController.h b/Classes/UI/Main/RenameFileViewController.h similarity index 100% rename from RenameFileViewController.h rename to Classes/UI/Main/RenameFileViewController.h diff --git a/RenameFileViewController.m b/Classes/UI/Main/RenameFileViewController.m similarity index 100% rename from RenameFileViewController.m rename to Classes/UI/Main/RenameFileViewController.m diff --git a/RenameRemoteFileViewController.h b/Classes/UI/Main/RenameRemoteFileViewController.h similarity index 100% rename from RenameRemoteFileViewController.h rename to Classes/UI/Main/RenameRemoteFileViewController.h diff --git a/RenameRemoteFileViewController.m b/Classes/UI/Main/RenameRemoteFileViewController.m similarity index 100% rename from RenameRemoteFileViewController.m rename to Classes/UI/Main/RenameRemoteFileViewController.m diff --git a/SettingViewController.h b/Classes/UI/Main/SettingViewController.h similarity index 100% rename from SettingViewController.h rename to Classes/UI/Main/SettingViewController.h diff --git a/SettingViewController.m b/Classes/UI/Main/SettingViewController.m similarity index 100% rename from SettingViewController.m rename to Classes/UI/Main/SettingViewController.m diff --git a/MultiLineTableViewCellStyle2.h b/Classes/UI/MultiLineTableViewCellStyle2.h similarity index 100% rename from MultiLineTableViewCellStyle2.h rename to Classes/UI/MultiLineTableViewCellStyle2.h diff --git a/MultiLineTableViewCellStyle2.m b/Classes/UI/MultiLineTableViewCellStyle2.m similarity index 100% rename from MultiLineTableViewCellStyle2.m rename to Classes/UI/MultiLineTableViewCellStyle2.m diff --git a/PlainSectionHeader.h b/Classes/UI/PlainSectionHeader.h similarity index 100% rename from PlainSectionHeader.h rename to Classes/UI/PlainSectionHeader.h diff --git a/PlainSectionHeader.m b/Classes/UI/PlainSectionHeader.m similarity index 100% rename from PlainSectionHeader.m rename to Classes/UI/PlainSectionHeader.m diff --git a/DropboxFileView.xib b/DropboxFileView.xib new file mode 100644 index 0000000..9b37866 --- /dev/null +++ b/DropboxFileView.xib @@ -0,0 +1,272 @@ + + + + 1056 + 10J567 + 1306 + 1038.35 + 462.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 301 + + + YES + IBUITableView + IBUIActivityIndicatorView + IBUIView + IBProxyObject + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + YES + + + + + YES + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 292 + + YES + + + 274 + {320, 460} + + + + + 3 + MQA + + NO + YES + NO + + IBCocoaTouchFramework + NO + 1 + 0 + YES + 44 + 22 + 22 + + + + -2147483356 + {{141, 212}, {37, 37}} + + + + NO + IBCocoaTouchFramework + 0 + + + {320, 460} + + + + + 3 + MQA + + 2 + + + IBCocoaTouchFramework + + + + + YES + + + dataSource + + + + 6 + + + + delegate + + + + 7 + + + + activityIndicator + + + + 9 + + + + view + + + + 11 + + + + tableView + + + + 12 + + + + + YES + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 10 + + + YES + + + + + + + 4 + + + + + 8 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 10.IBPluginDependency + 4.IBEditorWindowLastContentRect + 4.IBPluginDependency + 8.IBPluginDependency + + + YES + DropboxFileViewController + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + {{329, 504}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + + + + YES + + + + + 12 + + + + YES + + DropboxFileViewController + UIViewController + + YES + + YES + activityIndicator + tableView + + + YES + UIActivityIndicatorView + UITableView + + + + YES + + YES + activityIndicator + tableView + + + YES + + activityIndicator + UIActivityIndicatorView + + + tableView + UITableView + + + + + IBProjectSource + ./Classes/DropboxFileViewController.h + + + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + 3 + 301 + + diff --git a/FileManager.m b/FileManager.m deleted file mode 100644 index eb92151..0000000 --- a/FileManager.m +++ /dev/null @@ -1,243 +0,0 @@ -// -// FileManager.m -// MyKeePass -// -// Created by Qiang Yu on 3/3/10. -// Copyright 2010 Qiang Yu. All rights reserved. -// - -#import - -//Keepass2 utils -#import - -#import "FileManager.h" -#import "ASIHTTPRequest.h" -#import "MyKeePassAppDelegate.h" -#import "ActivityView.h" - -@interface FileManager(PrivateMethods) --(id) readFileHelp:(NSString *) fileName withPassword:(NSString *)password; -@end - - -@implementation FileManager -@synthesize _kdbReader; -@synthesize _editable; -@synthesize _filename; -@synthesize _password; -@synthesize _dirty; -@synthesize _remoteFiles; - -#define KDB_PATH "Passwords" -#define DOWNLOAD_PATH "Download" - -#define KDB1_SUFFIX ".kdb" -#define KDB2_SUFFIX ".kdbx" - -static NSString * DATA_DIR; -static NSString * DOWNLOAD_DIR; -static NSString * DOWNLOAD_CONFIG; - -+(void)initialize{ - if ( self == [FileManager class] ) { -#if TARGET_IPHONE_SIMULATOR - DATA_DIR = @"/Volumes/Users/qiang/Desktop/"; - DOWNLOAD_DIR = DATA_DIR; -#else - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - DATA_DIR = [[(NSString *)[paths objectAtIndex:0] stringByAppendingPathComponent:@KDB_PATH] retain]; - DOWNLOAD_DIR = [[(NSString *)[paths objectAtIndex:0] stringByAppendingPathComponent:@DOWNLOAD_PATH] retain]; - NSFileManager * fileManager = [NSFileManager defaultManager]; - if(![fileManager fileExistsAtPath:DATA_DIR]){ - [fileManager createDirectoryAtPath:DATA_DIR withIntermediateDirectories:YES attributes:nil error:nil]; - } - if(![fileManager fileExistsAtPath:DOWNLOAD_DIR]){ - [fileManager createDirectoryAtPath:DOWNLOAD_DIR withIntermediateDirectories:YES attributes:nil error:nil]; - } -#endif - DOWNLOAD_CONFIG = [[DOWNLOAD_DIR stringByAppendingPathComponent:@".download"] retain]; - if(![[NSFileManager defaultManager] fileExistsAtPath:DOWNLOAD_CONFIG]){ - NSDictionary * dic = [[NSDictionary alloc]init]; - [dic writeToFile:DOWNLOAD_CONFIG atomically:YES]; - [dic release]; - } - } -} - -+(NSString *)dataDir{ - return DATA_DIR; -} - --(id)init{ - if(self = [super init]){ - self._remoteFiles = [NSMutableDictionary dictionaryWithContentsOfFile:DOWNLOAD_CONFIG]; - } - return self; -} - --(void)dealloc{ - [_remoteFiles release]; - [_password release]; - [_filename release]; - [_kdbReader release]; - [super dealloc]; -} - - --(id) readFile:(NSString *) fileName withPassword:(NSString *)password{ - self._filename = fileName; - return [self readFileHelp:[FileManager getFullFileName:fileName] withPassword:password]; -} - --(id) readFileHelp:(NSString *) fileName withPassword:(NSString *)password{ - self._password = password; - self._dirty = NO; - - WrapperNSData * source = [[WrapperNSData alloc]initWithContentsOfMappedFile:fileName]; - self._kdbReader = nil; - _kdbReader = [KdbReaderFactory newKdbReader:source]; - // - // only kdb3 file is editable so far - // - _editable = [_kdbReader isKindOfClass:[Kdb3Reader class]]; - [_kdbReader load:source withPassword:password]; - [source release]; - return [_kdbReader getKdbTree]; -} - -+(NSString *)getTempFileNameFromURL:(NSString *)url{ - ByteBuffer * buffer = [Utils createByteBufferForString:url coding:NSUTF8StringEncoding]; - uint8_t hash[20]; - CC_SHA1(buffer._bytes, buffer._size, hash); - [buffer release]; - NSString * filename = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], - hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19], nil]; - - return [DOWNLOAD_DIR stringByAppendingPathComponent:filename]; -} - --(id) readRemoteFile:(NSString *)filename withPassword:(NSString *)password useCached:(BOOL)useCached username:(NSString *)username userpass:(NSString *)userpass domain:(NSString *)domain{ - self._filename = filename; - - NSString * url = [self getURLForRemoteFile:filename]; - - if(!url) @throw [NSException exceptionWithName:@"DownloadError" reason:@"DownloadError" userInfo:nil]; - - NSString * cacheFileName = [FileManager getTempFileNameFromURL:url]; - NSString * tmp = [cacheFileName stringByAppendingString:@".tmp"]; - - NSFileManager * fileManager = [NSFileManager defaultManager]; - - if([fileManager fileExistsAtPath:cacheFileName]&&useCached){ - id tree = [self readFileHelp:cacheFileName withPassword:password]; - _editable = NO; - return tree; - } - - ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]]; - [request setDownloadDestinationPath:tmp]; - - if([username length]) - [request setUsername:username]; - if([userpass length]) - [request setPassword:userpass]; - if([domain length]) - [request setDomain:domain]; - - [request startSynchronous]; - - int statusCode = [request responseStatusCode]; - - if(statusCode!=200){ - if(statusCode==401){ - @throw [NSException exceptionWithName:@"RemoteAuthenticationError" reason:@"RemoteAuthenticationError" userInfo:nil]; - }else{ - @throw [NSException exceptionWithName:@"DownloadError" reason:@"DownloadError" userInfo:nil]; - } - } - - [[NSFileManager defaultManager] removeItemAtPath:cacheFileName error:nil]; - [[NSFileManager defaultManager] moveItemAtPath:tmp toPath:cacheFileName error:nil]; - id tree = [self readFileHelp:cacheFileName withPassword:password]; - //remote file is not editable, yet - _editable = NO; - return tree; -} - --(void)getKDBFiles:(NSMutableArray *)list{ - [list removeAllObjects]; - - //kdb/kdbx files - NSFileManager * fileManager = [NSFileManager defaultManager]; - NSArray * contents = [fileManager contentsOfDirectoryAtPath:DATA_DIR error:nil]; - for(NSString * fileName in contents){ - if(![fileName hasPrefix:@"."]){ - [list addObject:fileName]; - } - } - [list sortUsingSelector:@selector(caseInsensitiveCompare:)]; -} - --(void)getRemoteFiles:(NSMutableArray *)list{ - [list removeAllObjects]; - [list addObjectsFromArray:[_remoteFiles keysSortedByValueUsingSelector:@selector(caseInsensitiveCompare:)]]; - [list sortUsingSelector:@selector(compare:)]; -} - --(void)addRemoteFile:(NSString *)name Url:(NSString *)url{ - [_remoteFiles setObject:url forKey:name]; - [_remoteFiles writeToFile:DOWNLOAD_CONFIG atomically:YES]; -} - --(NSString *)getURLForRemoteFile:(NSString *)name{ - return [_remoteFiles objectForKey:name]; -} - --(void)deleteLocalFile:(NSString *)filename{ - [[NSFileManager defaultManager] removeItemAtPath:[FileManager getFullFileName:filename] error:nil]; -} - --(void)deleteRemoteFile:(NSString *)name{ - [_remoteFiles removeObjectForKey:name]; - [_remoteFiles writeToFile:DOWNLOAD_CONFIG atomically:YES]; -} - --(NSUInteger) getKDBVersion{ - if([_kdbReader isKindOfClass:[Kdb3Reader class]]){ - return KDB_VERSION1; - }else{ - return KDB_VERSION2; - } -} - --(void)save{ - if(!_dirty) return; - if([_kdbReader isKindOfClass:[Kdb3Reader class]]){ - Kdb3Writer * writer = nil; - @try{ - writer = [[Kdb3Writer alloc]init]; - [writer persist:[_kdbReader getKdbTree] file:[FileManager getFullFileName:_filename] withPassword:_password]; - _dirty = NO; - }@finally { - [writer release]; - } - } -} - -+(NSString *)getFullFileName:(NSString *)filename{ - return [DATA_DIR stringByAppendingPathComponent:filename]; -} - -+(void)newKdb3File:(NSString *)filename withPassword:(NSString *)password{ - Kdb3Writer * writer = nil; - @try{ - writer = [[Kdb3Writer alloc]init]; - [writer newFile:[FileManager getFullFileName:filename] withPassword:password]; - }@finally { - [writer release]; - } -} - -@end diff --git a/MyKeePass.xcodeproj/project.pbxproj b/MyKeePass.xcodeproj/project.pbxproj index bed1023..836f95c 100755 --- a/MyKeePass.xcodeproj/project.pbxproj +++ b/MyKeePass.xcodeproj/project.pbxproj @@ -10,6 +10,53 @@ 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; }; + 485275FE137698B0007CDA4F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 485275FD137698B0007CDA4F /* Security.framework */; }; + 485276571376992B007CDA4F /* DBAccountInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276021376992B007CDA4F /* DBAccountInfo.m */; }; + 485276581376992B007CDA4F /* DBCreateAccountController.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276041376992B007CDA4F /* DBCreateAccountController.m */; }; + 485276591376992B007CDA4F /* DBError.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276061376992B007CDA4F /* DBError.m */; }; + 4852765A1376992B007CDA4F /* DBLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276081376992B007CDA4F /* DBLoadingView.m */; }; + 4852765B1376992B007CDA4F /* DBLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852760A1376992B007CDA4F /* DBLoginController.m */; }; + 4852765C1376992B007CDA4F /* DBMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852760C1376992B007CDA4F /* DBMetadata.m */; }; + 4852765D1376992B007CDA4F /* DBQuota.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852760E1376992B007CDA4F /* DBQuota.m */; }; + 4852765E1376992B007CDA4F /* DBRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276101376992B007CDA4F /* DBRequest.m */; }; + 4852765F1376992B007CDA4F /* DBRestClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276121376992B007CDA4F /* DBRestClient.m */; }; + 485276601376992B007CDA4F /* DBSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276141376992B007CDA4F /* DBSession.m */; }; + 485276611376992B007CDA4F /* NSObject+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276191376992B007CDA4F /* NSObject+SBJSON.m */; }; + 485276621376992B007CDA4F /* NSString+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852761B1376992B007CDA4F /* NSString+SBJSON.m */; }; + 485276631376992B007CDA4F /* SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852761D1376992B007CDA4F /* SBJSON.m */; }; + 485276641376992B007CDA4F /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852761F1376992B007CDA4F /* SBJsonBase.m */; }; + 485276651376992B007CDA4F /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276211376992B007CDA4F /* SBJsonParser.m */; }; + 485276661376992B007CDA4F /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276231376992B007CDA4F /* SBJsonWriter.m */; }; + 485276671376992B007CDA4F /* Base64Transcoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 485276261376992B007CDA4F /* Base64Transcoder.c */; }; + 485276681376992B007CDA4F /* MPOAuthAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852762B1376992B007CDA4F /* MPOAuthAPI.m */; }; + 485276691376992B007CDA4F /* MPOAuthAPIRequestLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852762D1376992B007CDA4F /* MPOAuthAPIRequestLoader.m */; }; + 4852766A1376992B007CDA4F /* MPOAuthAuthenticationMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852762F1376992B007CDA4F /* MPOAuthAuthenticationMethod.m */; }; + 4852766B1376992B007CDA4F /* MPOAuthAuthenticationMethodOAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276311376992B007CDA4F /* MPOAuthAuthenticationMethodOAuth.m */; }; + 4852766C1376992B007CDA4F /* MPOAuthConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276331376992B007CDA4F /* MPOAuthConnection.m */; }; + 4852766D1376992B007CDA4F /* MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276341376992B007CDA4F /* MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m */; }; + 4852766E1376992B007CDA4F /* MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276361376992B007CDA4F /* MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m */; }; + 4852766F1376992B007CDA4F /* MPOAuthCredentialConcreteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276381376992B007CDA4F /* MPOAuthCredentialConcreteStore.m */; }; + 485276701376992B007CDA4F /* MPOAuthSignatureParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852763C1376992B007CDA4F /* MPOAuthSignatureParameter.m */; }; + 485276711376992B007CDA4F /* MPOAuthURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852763E1376992B007CDA4F /* MPOAuthURLRequest.m */; }; + 485276721376992B007CDA4F /* MPOAuthURLResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276401376992B007CDA4F /* MPOAuthURLResponse.m */; }; + 485276731376992B007CDA4F /* MPURLRequestParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276421376992B007CDA4F /* MPURLRequestParameter.m */; }; + 485276741376992B007CDA4F /* NSString+URLEscapingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276441376992B007CDA4F /* NSString+URLEscapingAdditions.m */; }; + 485276751376992B007CDA4F /* NSURL+MPURLParameterAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276461376992B007CDA4F /* NSURL+MPURLParameterAdditions.m */; }; + 485276761376992B007CDA4F /* NSURLResponse+Encoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 485276481376992B007CDA4F /* NSURLResponse+Encoding.m */; }; + 485276771376992B007CDA4F /* NSString+Dropbox.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852764A1376992B007CDA4F /* NSString+Dropbox.m */; }; + 485276781376992B007CDA4F /* db_background.png in Resources */ = {isa = PBXBuildFile; fileRef = 4852764C1376992B007CDA4F /* db_background.png */; }; + 485276791376992B007CDA4F /* db_create_account.png in Resources */ = {isa = PBXBuildFile; fileRef = 4852764D1376992B007CDA4F /* db_create_account.png */; }; + 4852767A1376992B007CDA4F /* db_create_account@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4852764E1376992B007CDA4F /* db_create_account@2x.png */; }; + 4852767B1376992B007CDA4F /* db_create_account_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 4852764F1376992B007CDA4F /* db_create_account_button.png */; }; + 4852767C1376992B007CDA4F /* db_create_account_button_down.png in Resources */ = {isa = PBXBuildFile; fileRef = 485276501376992B007CDA4F /* db_create_account_button_down.png */; }; + 4852767D1376992B007CDA4F /* db_link_button.png in Resources */ = {isa = PBXBuildFile; fileRef = 485276511376992B007CDA4F /* db_link_button.png */; }; + 4852767E1376992B007CDA4F /* db_link_button_down.png in Resources */ = {isa = PBXBuildFile; fileRef = 485276521376992B007CDA4F /* db_link_button_down.png */; }; + 4852767F1376992B007CDA4F /* db_link_header.png in Resources */ = {isa = PBXBuildFile; fileRef = 485276531376992B007CDA4F /* db_link_header.png */; }; + 485276801376992B007CDA4F /* db_link_header@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 485276541376992B007CDA4F /* db_link_header@2x.png */; }; + 485276811376992B007CDA4F /* db_logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 485276551376992B007CDA4F /* db_logo.png */; }; + 485276821376992B007CDA4F /* db_logo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 485276561376992B007CDA4F /* db_logo@2x.png */; }; + 4852769913769EBA007CDA4F /* DropboxFileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4852769813769EBA007CDA4F /* DropboxFileViewController.m */; }; + 4852769B13769EDA007CDA4F /* DropboxFileView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4852769A13769EDA007CDA4F /* DropboxFileView.xib */; }; F716539E115DBD090017DC12 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = F716539D115DBD090017DC12 /* Default.png */; }; F78F24AF10E4740C0073C213 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F78F24AE10E4740C0073C213 /* CFNetwork.framework */; }; F7DA414B10CB60FC00F1D072 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7DA414A10CB60FC00F1D072 /* QuartzCore.framework */; }; @@ -116,6 +163,93 @@ 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 32CA4F630368D1EE00C91783 /* MyKeePass_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyKeePass_Prefix.pch; sourceTree = ""; }; + 485275FD137698B0007CDA4F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 485275FF1376990C007CDA4F /* DropboxAPIKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DropboxAPIKeys.h; sourceTree = ""; }; + 485276011376992B007CDA4F /* DBAccountInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBAccountInfo.h; sourceTree = ""; }; + 485276021376992B007CDA4F /* DBAccountInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBAccountInfo.m; sourceTree = ""; }; + 485276031376992B007CDA4F /* DBCreateAccountController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBCreateAccountController.h; sourceTree = ""; }; + 485276041376992B007CDA4F /* DBCreateAccountController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBCreateAccountController.m; sourceTree = ""; }; + 485276051376992B007CDA4F /* DBError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBError.h; sourceTree = ""; }; + 485276061376992B007CDA4F /* DBError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBError.m; sourceTree = ""; }; + 485276071376992B007CDA4F /* DBLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBLoadingView.h; sourceTree = ""; }; + 485276081376992B007CDA4F /* DBLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBLoadingView.m; sourceTree = ""; }; + 485276091376992B007CDA4F /* DBLoginController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBLoginController.h; sourceTree = ""; }; + 4852760A1376992B007CDA4F /* DBLoginController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBLoginController.m; sourceTree = ""; }; + 4852760B1376992B007CDA4F /* DBMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBMetadata.h; sourceTree = ""; }; + 4852760C1376992B007CDA4F /* DBMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBMetadata.m; sourceTree = ""; }; + 4852760D1376992B007CDA4F /* DBQuota.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBQuota.h; sourceTree = ""; }; + 4852760E1376992B007CDA4F /* DBQuota.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBQuota.m; sourceTree = ""; }; + 4852760F1376992B007CDA4F /* DBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBRequest.h; sourceTree = ""; }; + 485276101376992B007CDA4F /* DBRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBRequest.m; sourceTree = ""; }; + 485276111376992B007CDA4F /* DBRestClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBRestClient.h; sourceTree = ""; }; + 485276121376992B007CDA4F /* DBRestClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBRestClient.m; sourceTree = ""; }; + 485276131376992B007CDA4F /* DBSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBSession.h; sourceTree = ""; }; + 485276141376992B007CDA4F /* DBSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBSession.m; sourceTree = ""; }; + 485276151376992B007CDA4F /* DropboxSDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DropboxSDK.h; sourceTree = ""; }; + 485276171376992B007CDA4F /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; + 485276181376992B007CDA4F /* NSObject+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJSON.h"; sourceTree = ""; }; + 485276191376992B007CDA4F /* NSObject+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJSON.m"; sourceTree = ""; }; + 4852761A1376992B007CDA4F /* NSString+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SBJSON.h"; sourceTree = ""; }; + 4852761B1376992B007CDA4F /* NSString+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SBJSON.m"; sourceTree = ""; }; + 4852761C1376992B007CDA4F /* SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJSON.h; sourceTree = ""; }; + 4852761D1376992B007CDA4F /* SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJSON.m; sourceTree = ""; }; + 4852761E1376992B007CDA4F /* SBJsonBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonBase.h; sourceTree = ""; }; + 4852761F1376992B007CDA4F /* SBJsonBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonBase.m; sourceTree = ""; }; + 485276201376992B007CDA4F /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; + 485276211376992B007CDA4F /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; + 485276221376992B007CDA4F /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; + 485276231376992B007CDA4F /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; + 485276261376992B007CDA4F /* Base64Transcoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Base64Transcoder.c; sourceTree = ""; }; + 485276271376992B007CDA4F /* Base64Transcoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Base64Transcoder.h; sourceTree = ""; }; + 485276281376992B007CDA4F /* MPDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPDebug.h; sourceTree = ""; }; + 485276291376992B007CDA4F /* MPOAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuth.h; sourceTree = ""; }; + 4852762A1376992B007CDA4F /* MPOAuthAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthAPI.h; sourceTree = ""; }; + 4852762B1376992B007CDA4F /* MPOAuthAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthAPI.m; sourceTree = ""; }; + 4852762C1376992B007CDA4F /* MPOAuthAPIRequestLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthAPIRequestLoader.h; sourceTree = ""; }; + 4852762D1376992B007CDA4F /* MPOAuthAPIRequestLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthAPIRequestLoader.m; sourceTree = ""; }; + 4852762E1376992B007CDA4F /* MPOAuthAuthenticationMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthAuthenticationMethod.h; sourceTree = ""; }; + 4852762F1376992B007CDA4F /* MPOAuthAuthenticationMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthAuthenticationMethod.m; sourceTree = ""; }; + 485276301376992B007CDA4F /* MPOAuthAuthenticationMethodOAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthAuthenticationMethodOAuth.h; sourceTree = ""; }; + 485276311376992B007CDA4F /* MPOAuthAuthenticationMethodOAuth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthAuthenticationMethodOAuth.m; sourceTree = ""; }; + 485276321376992B007CDA4F /* MPOAuthConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthConnection.h; sourceTree = ""; }; + 485276331376992B007CDA4F /* MPOAuthConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthConnection.m; sourceTree = ""; }; + 485276341376992B007CDA4F /* MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m"; sourceTree = ""; }; + 485276351376992B007CDA4F /* MPOAuthCredentialConcreteStore+KeychainAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MPOAuthCredentialConcreteStore+KeychainAdditions.h"; sourceTree = ""; }; + 485276361376992B007CDA4F /* MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m"; sourceTree = ""; }; + 485276371376992B007CDA4F /* MPOAuthCredentialConcreteStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthCredentialConcreteStore.h; sourceTree = ""; }; + 485276381376992B007CDA4F /* MPOAuthCredentialConcreteStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthCredentialConcreteStore.m; sourceTree = ""; }; + 485276391376992B007CDA4F /* MPOAuthCredentialStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthCredentialStore.h; sourceTree = ""; }; + 4852763A1376992B007CDA4F /* MPOAuthParameterFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthParameterFactory.h; sourceTree = ""; }; + 4852763B1376992B007CDA4F /* MPOAuthSignatureParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthSignatureParameter.h; sourceTree = ""; }; + 4852763C1376992B007CDA4F /* MPOAuthSignatureParameter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthSignatureParameter.m; sourceTree = ""; }; + 4852763D1376992B007CDA4F /* MPOAuthURLRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthURLRequest.h; sourceTree = ""; }; + 4852763E1376992B007CDA4F /* MPOAuthURLRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthURLRequest.m; sourceTree = ""; }; + 4852763F1376992B007CDA4F /* MPOAuthURLResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOAuthURLResponse.h; sourceTree = ""; }; + 485276401376992B007CDA4F /* MPOAuthURLResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOAuthURLResponse.m; sourceTree = ""; }; + 485276411376992B007CDA4F /* MPURLRequestParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPURLRequestParameter.h; sourceTree = ""; }; + 485276421376992B007CDA4F /* MPURLRequestParameter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPURLRequestParameter.m; sourceTree = ""; }; + 485276431376992B007CDA4F /* NSString+URLEscapingAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+URLEscapingAdditions.h"; sourceTree = ""; }; + 485276441376992B007CDA4F /* NSString+URLEscapingAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+URLEscapingAdditions.m"; sourceTree = ""; }; + 485276451376992B007CDA4F /* NSURL+MPURLParameterAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+MPURLParameterAdditions.h"; sourceTree = ""; }; + 485276461376992B007CDA4F /* NSURL+MPURLParameterAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+MPURLParameterAdditions.m"; sourceTree = ""; }; + 485276471376992B007CDA4F /* NSURLResponse+Encoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLResponse+Encoding.h"; sourceTree = ""; }; + 485276481376992B007CDA4F /* NSURLResponse+Encoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLResponse+Encoding.m"; sourceTree = ""; }; + 485276491376992B007CDA4F /* NSString+Dropbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Dropbox.h"; sourceTree = ""; }; + 4852764A1376992B007CDA4F /* NSString+Dropbox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Dropbox.m"; sourceTree = ""; }; + 4852764C1376992B007CDA4F /* db_background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = db_background.png; sourceTree = ""; }; + 4852764D1376992B007CDA4F /* db_create_account.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = db_create_account.png; sourceTree = ""; }; + 4852764E1376992B007CDA4F /* db_create_account@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "db_create_account@2x.png"; sourceTree = ""; }; + 4852764F1376992B007CDA4F /* db_create_account_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = db_create_account_button.png; sourceTree = ""; }; + 485276501376992B007CDA4F /* db_create_account_button_down.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = db_create_account_button_down.png; sourceTree = ""; }; + 485276511376992B007CDA4F /* db_link_button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = db_link_button.png; sourceTree = ""; }; + 485276521376992B007CDA4F /* db_link_button_down.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = db_link_button_down.png; sourceTree = ""; }; + 485276531376992B007CDA4F /* db_link_header.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = db_link_header.png; sourceTree = ""; }; + 485276541376992B007CDA4F /* db_link_header@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "db_link_header@2x.png"; sourceTree = ""; }; + 485276551376992B007CDA4F /* db_logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = db_logo.png; sourceTree = ""; }; + 485276561376992B007CDA4F /* db_logo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "db_logo@2x.png"; sourceTree = ""; }; + 4852769713769EBA007CDA4F /* DropboxFileViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DropboxFileViewController.h; sourceTree = ""; }; + 4852769813769EBA007CDA4F /* DropboxFileViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DropboxFileViewController.m; sourceTree = ""; }; + 4852769A13769EDA007CDA4F /* DropboxFileView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DropboxFileView.xib; sourceTree = ""; }; 8D1107310486CEB800E47090 /* MyKeePass-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "MyKeePass-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; F716539D115DBD090017DC12 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; F78F24AE10E4740C0073C213 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; @@ -259,6 +393,7 @@ F7DDD0D3115DB58000FD4EE3 /* SystemConfiguration.framework in Frameworks */, F7DDD0D7115DB58500FD4EE3 /* MessageUI.framework in Frameworks */, F7DDD100115DB6B000FD4EE3 /* libKeePass2.a in Frameworks */, + 485275FE137698B0007CDA4F /* Security.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -304,6 +439,7 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( + 4852769A13769EDA007CDA4F /* DropboxFileView.xib */, F7DDD09A115DB18200FD4EE3 /* MainWindow.xib */, 8D1107310486CEB800E47090 /* MyKeePass-Info.plist */, ); @@ -313,6 +449,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + 485275FD137698B0007CDA4F /* Security.framework */, F7DA414A10CB60FC00F1D072 /* QuartzCore.framework */, 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 1D30AB110D05D00D00671497 /* Foundation.framework */, @@ -322,6 +459,128 @@ name = Frameworks; sourceTree = ""; }; + 485276001376992B007CDA4F /* DropboxSDK */ = { + isa = PBXGroup; + children = ( + 485276011376992B007CDA4F /* DBAccountInfo.h */, + 485276021376992B007CDA4F /* DBAccountInfo.m */, + 485276031376992B007CDA4F /* DBCreateAccountController.h */, + 485276041376992B007CDA4F /* DBCreateAccountController.m */, + 485276051376992B007CDA4F /* DBError.h */, + 485276061376992B007CDA4F /* DBError.m */, + 485276071376992B007CDA4F /* DBLoadingView.h */, + 485276081376992B007CDA4F /* DBLoadingView.m */, + 485276091376992B007CDA4F /* DBLoginController.h */, + 4852760A1376992B007CDA4F /* DBLoginController.m */, + 4852760B1376992B007CDA4F /* DBMetadata.h */, + 4852760C1376992B007CDA4F /* DBMetadata.m */, + 4852760D1376992B007CDA4F /* DBQuota.h */, + 4852760E1376992B007CDA4F /* DBQuota.m */, + 4852760F1376992B007CDA4F /* DBRequest.h */, + 485276101376992B007CDA4F /* DBRequest.m */, + 485276111376992B007CDA4F /* DBRestClient.h */, + 485276121376992B007CDA4F /* DBRestClient.m */, + 485276131376992B007CDA4F /* DBSession.h */, + 485276141376992B007CDA4F /* DBSession.m */, + 485276151376992B007CDA4F /* DropboxSDK.h */, + 485276161376992B007CDA4F /* JSON */, + 485276241376992B007CDA4F /* MPOAuth */, + 485276491376992B007CDA4F /* NSString+Dropbox.h */, + 4852764A1376992B007CDA4F /* NSString+Dropbox.m */, + 4852764B1376992B007CDA4F /* Resources */, + ); + name = DropboxSDK; + path = ThirdParty/DropboxSDK; + sourceTree = ""; + }; + 485276161376992B007CDA4F /* JSON */ = { + isa = PBXGroup; + children = ( + 485276171376992B007CDA4F /* JSON.h */, + 485276181376992B007CDA4F /* NSObject+SBJSON.h */, + 485276191376992B007CDA4F /* NSObject+SBJSON.m */, + 4852761A1376992B007CDA4F /* NSString+SBJSON.h */, + 4852761B1376992B007CDA4F /* NSString+SBJSON.m */, + 4852761C1376992B007CDA4F /* SBJSON.h */, + 4852761D1376992B007CDA4F /* SBJSON.m */, + 4852761E1376992B007CDA4F /* SBJsonBase.h */, + 4852761F1376992B007CDA4F /* SBJsonBase.m */, + 485276201376992B007CDA4F /* SBJsonParser.h */, + 485276211376992B007CDA4F /* SBJsonParser.m */, + 485276221376992B007CDA4F /* SBJsonWriter.h */, + 485276231376992B007CDA4F /* SBJsonWriter.m */, + ); + path = JSON; + sourceTree = ""; + }; + 485276241376992B007CDA4F /* MPOAuth */ = { + isa = PBXGroup; + children = ( + 485276251376992B007CDA4F /* Crypto */, + 485276281376992B007CDA4F /* MPDebug.h */, + 485276291376992B007CDA4F /* MPOAuth.h */, + 4852762A1376992B007CDA4F /* MPOAuthAPI.h */, + 4852762B1376992B007CDA4F /* MPOAuthAPI.m */, + 4852762C1376992B007CDA4F /* MPOAuthAPIRequestLoader.h */, + 4852762D1376992B007CDA4F /* MPOAuthAPIRequestLoader.m */, + 4852762E1376992B007CDA4F /* MPOAuthAuthenticationMethod.h */, + 4852762F1376992B007CDA4F /* MPOAuthAuthenticationMethod.m */, + 485276301376992B007CDA4F /* MPOAuthAuthenticationMethodOAuth.h */, + 485276311376992B007CDA4F /* MPOAuthAuthenticationMethodOAuth.m */, + 485276321376992B007CDA4F /* MPOAuthConnection.h */, + 485276331376992B007CDA4F /* MPOAuthConnection.m */, + 485276341376992B007CDA4F /* MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m */, + 485276351376992B007CDA4F /* MPOAuthCredentialConcreteStore+KeychainAdditions.h */, + 485276361376992B007CDA4F /* MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m */, + 485276371376992B007CDA4F /* MPOAuthCredentialConcreteStore.h */, + 485276381376992B007CDA4F /* MPOAuthCredentialConcreteStore.m */, + 485276391376992B007CDA4F /* MPOAuthCredentialStore.h */, + 4852763A1376992B007CDA4F /* MPOAuthParameterFactory.h */, + 4852763B1376992B007CDA4F /* MPOAuthSignatureParameter.h */, + 4852763C1376992B007CDA4F /* MPOAuthSignatureParameter.m */, + 4852763D1376992B007CDA4F /* MPOAuthURLRequest.h */, + 4852763E1376992B007CDA4F /* MPOAuthURLRequest.m */, + 4852763F1376992B007CDA4F /* MPOAuthURLResponse.h */, + 485276401376992B007CDA4F /* MPOAuthURLResponse.m */, + 485276411376992B007CDA4F /* MPURLRequestParameter.h */, + 485276421376992B007CDA4F /* MPURLRequestParameter.m */, + 485276431376992B007CDA4F /* NSString+URLEscapingAdditions.h */, + 485276441376992B007CDA4F /* NSString+URLEscapingAdditions.m */, + 485276451376992B007CDA4F /* NSURL+MPURLParameterAdditions.h */, + 485276461376992B007CDA4F /* NSURL+MPURLParameterAdditions.m */, + 485276471376992B007CDA4F /* NSURLResponse+Encoding.h */, + 485276481376992B007CDA4F /* NSURLResponse+Encoding.m */, + ); + path = MPOAuth; + sourceTree = ""; + }; + 485276251376992B007CDA4F /* Crypto */ = { + isa = PBXGroup; + children = ( + 485276261376992B007CDA4F /* Base64Transcoder.c */, + 485276271376992B007CDA4F /* Base64Transcoder.h */, + ); + path = Crypto; + sourceTree = ""; + }; + 4852764B1376992B007CDA4F /* Resources */ = { + isa = PBXGroup; + children = ( + 4852764C1376992B007CDA4F /* db_background.png */, + 4852764D1376992B007CDA4F /* db_create_account.png */, + 4852764E1376992B007CDA4F /* db_create_account@2x.png */, + 4852764F1376992B007CDA4F /* db_create_account_button.png */, + 485276501376992B007CDA4F /* db_create_account_button_down.png */, + 485276511376992B007CDA4F /* db_link_button.png */, + 485276521376992B007CDA4F /* db_link_button_down.png */, + 485276531376992B007CDA4F /* db_link_header.png */, + 485276541376992B007CDA4F /* db_link_header@2x.png */, + 485276551376992B007CDA4F /* db_logo.png */, + 485276561376992B007CDA4F /* db_logo@2x.png */, + ); + path = Resources; + sourceTree = ""; + }; F7DDCFD6115DB11B00FD4EE3 /* Classes */ = { isa = PBXGroup; children = ( @@ -329,13 +588,15 @@ F7DDD013115DB13500FD4EE3 /* UI */, F7DDD04C115DB13500FD4EE3 /* MyKeePassAppDelegate.h */, F7DDD04D115DB13500FD4EE3 /* MyKeePassAppDelegate.m */, + 485275FF1376990C007CDA4F /* DropboxAPIKeys.h */, ); - name = Classes; + path = Classes; sourceTree = ""; }; F7DDCFE0115DB13500FD4EE3 /* ThirdParty */ = { isa = PBXGroup; children = ( + 485276001376992B007CDA4F /* DropboxSDK */, F7DDD00A115DB13500FD4EE3 /* Tapku */, F7DDCFFA115DB13500FD4EE3 /* ASIHTTPRequest */, F7DDCFE1115DB13500FD4EE3 /* CocoaHttpServer */, @@ -352,6 +613,7 @@ F7DDCFE2115DB13500FD4EE3 /* HTTP */, ); name = CocoaHttpServer; + path = ThirdParty/CocoaHttpServer; sourceTree = ""; }; F7DDCFE2115DB13500FD4EE3 /* HTTP */ = { @@ -366,7 +628,7 @@ F7DDCFE9115DB13500FD4EE3 /* HTTPAuthenticationRequest.h */, F7DDCFEA115DB13500FD4EE3 /* HTTPAuthenticationRequest.m */, ); - name = HTTP; + path = HTTP; sourceTree = ""; }; F7DDCFEB115DB13500FD4EE3 /* TCP */ = { @@ -375,7 +637,7 @@ F7DDCFEC115DB13500FD4EE3 /* AsyncSocket.h */, F7DDCFED115DB13500FD4EE3 /* AsyncSocket.m */, ); - name = TCP; + path = TCP; sourceTree = ""; }; F7DDCFEE115DB13500FD4EE3 /* Categories */ = { @@ -388,7 +650,7 @@ F7DDCFF3115DB13500FD4EE3 /* DDData.h */, F7DDCFF4115DB13500FD4EE3 /* DDData.m */, ); - name = Categories; + path = Categories; sourceTree = ""; }; F7DDCFF5115DB13500FD4EE3 /* Classes */ = { @@ -399,7 +661,7 @@ F7DDCFF8115DB13500FD4EE3 /* localhostAddresses.h */, F7DDCFF9115DB13500FD4EE3 /* localhostAddresses.m */, ); - name = Classes; + path = Classes; sourceTree = ""; }; F7DDCFFA115DB13500FD4EE3 /* ASIHTTPRequest */ = { @@ -422,6 +684,7 @@ F7DDD009115DB13500FD4EE3 /* ASIAuthenticationDialog.m */, ); name = ASIHTTPRequest; + path = ThirdParty/ASIHTTPRequest; sourceTree = ""; }; F7DDD00A115DB13500FD4EE3 /* Tapku */ = { @@ -437,6 +700,7 @@ F7DDD012115DB13500FD4EE3 /* TKLabelTextFieldCell.m */, ); name = Tapku; + path = ThirdParty/Tapku; sourceTree = ""; }; F7DDD013115DB13500FD4EE3 /* UI */ = { @@ -457,7 +721,7 @@ F7DDD018115DB13500FD4EE3 /* MultiLineTableViewCellStyle2.h */, F7DDD019115DB13500FD4EE3 /* MultiLineTableViewCellStyle2.m */, ); - name = UI; + path = UI; sourceTree = ""; }; F7DDD01A115DB13500FD4EE3 /* Kdb */ = { @@ -486,7 +750,7 @@ F7DDD02F115DB13500FD4EE3 /* OptionViewController.h */, F7DDD030115DB13500FD4EE3 /* OptionViewController.m */, ); - name = Kdb; + path = Kdb; sourceTree = ""; }; F7DDD031115DB13500FD4EE3 /* Main */ = { @@ -512,8 +776,10 @@ F7DDD043115DB13500FD4EE3 /* FileUploadViewController.m */, F7DDD044115DB13500FD4EE3 /* FileManagerOperation.h */, F7DDD045115DB13500FD4EE3 /* FileManagerOperation.m */, + 4852769713769EBA007CDA4F /* DropboxFileViewController.h */, + 4852769813769EBA007CDA4F /* DropboxFileViewController.m */, ); - name = Main; + path = Main; sourceTree = ""; }; F7DDD07F115DB15B00FD4EE3 /* images */ = { @@ -535,7 +801,7 @@ F7DDD08A115DB15B00FD4EE3 /* kdb.png */, F7DDD08B115DB15B00FD4EE3 /* kdbx.png */, ); - name = images; + path = images; sourceTree = ""; }; F7DDD0A4115DB21E00FD4EE3 /* Products */ = { @@ -575,7 +841,11 @@ isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MyKeePass" */; compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; hasScannedForEncodings = 1; + knownRegions = ( + en, + ); mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; projectDirPath = ""; projectReferences = ( @@ -629,6 +899,18 @@ F7DDD117115DB80A00FD4EE3 /* Icon-Small.png in Resources */, F7DDD118115DB80A00FD4EE3 /* Icon.png in Resources */, F716539E115DBD090017DC12 /* Default.png in Resources */, + 485276781376992B007CDA4F /* db_background.png in Resources */, + 485276791376992B007CDA4F /* db_create_account.png in Resources */, + 4852767A1376992B007CDA4F /* db_create_account@2x.png in Resources */, + 4852767B1376992B007CDA4F /* db_create_account_button.png in Resources */, + 4852767C1376992B007CDA4F /* db_create_account_button_down.png in Resources */, + 4852767D1376992B007CDA4F /* db_link_button.png in Resources */, + 4852767E1376992B007CDA4F /* db_link_button_down.png in Resources */, + 4852767F1376992B007CDA4F /* db_link_header.png in Resources */, + 485276801376992B007CDA4F /* db_link_header@2x.png in Resources */, + 485276811376992B007CDA4F /* db_logo.png in Resources */, + 485276821376992B007CDA4F /* db_logo@2x.png in Resources */, + 4852769B13769EDA007CDA4F /* DropboxFileView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -689,6 +971,40 @@ F7DDD07D115DB13500FD4EE3 /* AboutViewController.m in Sources */, F7DDD07E115DB13500FD4EE3 /* MyKeePassAppDelegate.m in Sources */, F7DDD099115DB16800FD4EE3 /* main.m in Sources */, + 485276571376992B007CDA4F /* DBAccountInfo.m in Sources */, + 485276581376992B007CDA4F /* DBCreateAccountController.m in Sources */, + 485276591376992B007CDA4F /* DBError.m in Sources */, + 4852765A1376992B007CDA4F /* DBLoadingView.m in Sources */, + 4852765B1376992B007CDA4F /* DBLoginController.m in Sources */, + 4852765C1376992B007CDA4F /* DBMetadata.m in Sources */, + 4852765D1376992B007CDA4F /* DBQuota.m in Sources */, + 4852765E1376992B007CDA4F /* DBRequest.m in Sources */, + 4852765F1376992B007CDA4F /* DBRestClient.m in Sources */, + 485276601376992B007CDA4F /* DBSession.m in Sources */, + 485276611376992B007CDA4F /* NSObject+SBJSON.m in Sources */, + 485276621376992B007CDA4F /* NSString+SBJSON.m in Sources */, + 485276631376992B007CDA4F /* SBJSON.m in Sources */, + 485276641376992B007CDA4F /* SBJsonBase.m in Sources */, + 485276651376992B007CDA4F /* SBJsonParser.m in Sources */, + 485276661376992B007CDA4F /* SBJsonWriter.m in Sources */, + 485276671376992B007CDA4F /* Base64Transcoder.c in Sources */, + 485276681376992B007CDA4F /* MPOAuthAPI.m in Sources */, + 485276691376992B007CDA4F /* MPOAuthAPIRequestLoader.m in Sources */, + 4852766A1376992B007CDA4F /* MPOAuthAuthenticationMethod.m in Sources */, + 4852766B1376992B007CDA4F /* MPOAuthAuthenticationMethodOAuth.m in Sources */, + 4852766C1376992B007CDA4F /* MPOAuthConnection.m in Sources */, + 4852766D1376992B007CDA4F /* MPOAuthCredentiaIConcreteStore+KeychainAdditionsMac.m in Sources */, + 4852766E1376992B007CDA4F /* MPOAuthCredentialConcreteStore+KeychainAdditionsiPhone.m in Sources */, + 4852766F1376992B007CDA4F /* MPOAuthCredentialConcreteStore.m in Sources */, + 485276701376992B007CDA4F /* MPOAuthSignatureParameter.m in Sources */, + 485276711376992B007CDA4F /* MPOAuthURLRequest.m in Sources */, + 485276721376992B007CDA4F /* MPOAuthURLResponse.m in Sources */, + 485276731376992B007CDA4F /* MPURLRequestParameter.m in Sources */, + 485276741376992B007CDA4F /* NSString+URLEscapingAdditions.m in Sources */, + 485276751376992B007CDA4F /* NSURL+MPURLParameterAdditions.m in Sources */, + 485276761376992B007CDA4F /* NSURLResponse+Encoding.m in Sources */, + 485276771376992B007CDA4F /* NSString+Dropbox.m in Sources */, + 4852769913769EBA007CDA4F /* DropboxFileViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MyKeePassAppDelegate.h b/MyKeePassAppDelegate.h deleted file mode 100644 index 5c20d6d..0000000 --- a/MyKeePassAppDelegate.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// MyKeePassAppDelegate.h -// MyKeePass -// -// Created by Qiang Yu on 3/3/10. -// Copyright Qiang Yu 2010. All rights reserved. -// - -#import -#import "MainViewController.h" -#import "KdbViewController.h" -#import "PasswordViewController.h" -#import "FileManager.h" - -@interface MyKeePassAppDelegate : NSObject { - FileManager * _fileManager; - - MainViewController * _mainView; - KdbViewController * _kdbView; - - UIViewController * _currentViewController; - - UIWindow *window; -} - -@property (nonatomic, retain) IBOutlet UIWindow *window; -@property (nonatomic, readonly) FileManager * _fileManager; -@property (nonatomic, retain) MainViewController * _mainView; -@property (nonatomic, retain) KdbViewController * _kdbView; -@property (nonatomic, retain) UIViewController * _currentViewController; - -+(MyKeePassAppDelegate *)delegate; -+(UIWindow *)getWindow; - --(void)showKdb; --(void)showMainView; --(BOOL)isEditable; -@end - diff --git a/MyKeePassAppDelegate.m b/MyKeePassAppDelegate.m deleted file mode 100644 index aa70fde..0000000 --- a/MyKeePassAppDelegate.m +++ /dev/null @@ -1,108 +0,0 @@ -// -// MyKeePassAppDelegate.m -// MyKeePass -// -// Created by Qiang Yu on 3/3/10. -// Copyright Qiang Yu 2010. All rights reserved. -// - -#import -#import "MyKeePassAppDelegate.h" - -@implementation MyKeePassAppDelegate -@synthesize window; -@synthesize _fileManager; -@synthesize _kdbView; -@synthesize _mainView; -@synthesize _currentViewController; - -- (void)applicationDidFinishLaunching:(UIApplication *)application { - //initialize the file manager - _fileManager = [[FileManager alloc]init]; - - //initialize the main view - _mainView = [[MainViewController alloc]init]; - - self._currentViewController = _mainView; - - [window addSubview:_mainView.view]; - [window makeKeyAndVisible]; -} - - -- (void)dealloc { - [_mainView release]; - [_kdbView release]; - [window release]; - [_fileManager release]; - [_currentViewController release]; - [super dealloc]; -} - --(void)showKdb{ - if(![_currentViewController isKindOfClass:[KdbViewController class]]){ - [_currentViewController.view removeFromSuperview]; - id kdbReader = _fileManager._kdbReader; - - if(!_kdbView){ - _kdbView = [[KdbViewController alloc]initWithGroup:[[kdbReader getKdbTree] getRoot]]; - } - - self._currentViewController = _kdbView; - - [window addSubview:_currentViewController.view]; - - CATransition *animation = [CATransition animation]; - [animation setDuration:0.5]; - [animation setType:kCATransitionFade]; - [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; - [[window layer] addAnimation:animation forKey:@"SwitchToKdbView"]; - } -} - --(void)showMainView{ - if(![_currentViewController isKindOfClass:[MainViewController class]]){ - [_currentViewController.view removeFromSuperview]; - _fileManager._kdbReader = nil; - self._kdbView = nil; - - if(!_mainView) - _mainView = [[MainViewController alloc]init]; - - self._currentViewController = _mainView; - - [window addSubview:_currentViewController.view]; - - CATransition *animation = [CATransition animation]; - [animation setDuration:0.5]; - [animation setType:kCATransitionFade]; - [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; - [[window layer] addAnimation:animation forKey:@"SwitchToMainView"]; - } -} - -- (void)applicationDidBecomeActive:(UIApplication *)application{ - if([_currentViewController isKindOfClass:[KdbViewController class]]){ - [_currentViewController.view removeFromSuperview]; - - PasswordViewController * lockWindow = [[PasswordViewController alloc] initWithFileName:_fileManager._filename remote:NO]; - lockWindow._isReopen = YES; - - self._currentViewController = lockWindow; - [window addSubview:lockWindow.view]; - [lockWindow release]; - } -} - --(BOOL)isEditable{ - return _fileManager._editable; -} - -+(MyKeePassAppDelegate *)delegate{ - return (MyKeePassAppDelegate *)[[UIApplication sharedApplication] delegate]; -} - -+(UIWindow *)getWindow{ - return ((MyKeePassAppDelegate *)[[UIApplication sharedApplication] delegate]).window; -} -@end diff --git a/Default.png b/images/Default.png similarity index 100% rename from Default.png rename to images/Default.png diff --git a/Icon-Small.png b/images/Icon-Small.png similarity index 100% rename from Icon-Small.png rename to images/Icon-Small.png diff --git a/Icon.png b/images/Icon.png similarity index 100% rename from Icon.png rename to images/Icon.png diff --git a/about.png b/images/about.png similarity index 100% rename from about.png rename to images/about.png diff --git a/add.png b/images/add.png similarity index 100% rename from add.png rename to images/add.png diff --git a/addPressed.png b/images/addPressed.png similarity index 100% rename from addPressed.png rename to images/addPressed.png diff --git a/files.png b/images/files.png similarity index 100% rename from files.png rename to images/files.png diff --git a/http.png b/images/http.png similarity index 100% rename from http.png rename to images/http.png diff --git a/kdb.png b/images/kdb.png similarity index 100% rename from kdb.png rename to images/kdb.png diff --git a/kdbx.png b/images/kdbx.png similarity index 100% rename from kdbx.png rename to images/kdbx.png diff --git a/options.png b/images/options.png similarity index 100% rename from options.png rename to images/options.png diff --git a/password.png b/images/password.png similarity index 100% rename from password.png rename to images/password.png diff --git a/passwordPressed.png b/images/passwordPressed.png similarity index 100% rename from passwordPressed.png rename to images/passwordPressed.png diff --git a/passwords.png b/images/passwords.png similarity index 100% rename from passwords.png rename to images/passwords.png diff --git a/unknown.png b/images/unknown.png similarity index 100% rename from unknown.png rename to images/unknown.png