CocoaShare Start

This commit is contained in:
GRMrGecko 2011-02-01 09:51:02 -06:00
commit e44743fbae
334 changed files with 61301 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
build
*.zip
*.xcodeproj/*.pbxuser
*.xcodeproj/*.mode*
*.xcodeproj/*.perspective*
*.xcodeproj/xcuserdata
*.xcodeproj/project.xcworkspace/xcuserdata
*.xcworkspace/xcuserdata
CocoaShare/*
Screenshots/*

32
About.rtf Normal file
View File

@ -0,0 +1,32 @@
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\qc\pardirnatural
\f0\b\fs36 \cf0 By Mr. Gecko
\b0\fs32 \
\fs34 At {\field{\*\fldinst{HYPERLINK "http://mrgeckosmedia.com/"}}{\fldrslt mrgeckosmedia.com}}
\fs32 \
Special Thanks To\
\fs24 MegaEduX ({\field{\*\fldinst{HYPERLINK "http://megaedux.com"}}{\fldrslt megaedux.com}})\
PowerOfCheese ({\field{\*\fldinst{HYPERLINK "http://xtrememachinez.com"}}{\fldrslt xtrememachinez.com}})\
\
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\cf0 CocoaShare Uses {\field{\*\fldinst{HYPERLINK "http://sparkle.andymatuschak.org"}}{\fldrslt Sparkle}} for software update, {\field{\*\fldinst{HYPERLINK "http://growl.info/"}}{\fldrslt Growl}} for notifications, {\field{\*\fldinst{HYPERLINK "http://regexkit.sourceforge.net/"}}{\fldrslt RegexKit Lite}} as a {\field{\*\fldinst{HYPERLINK "http://site.icu-project.org/"}}{\fldrslt ICU}} regular expression wrapper, and {\field{\*\fldinst{HYPERLINK "https://www.dropbox.com/developers"}}{\fldrslt Dropbox API}} for {\field{\*\fldinst{HYPERLINK "https://www.dropbox.com/"}}{\fldrslt Dropbox}} support.\
\
CocoaShare makes it easy for you to share files with friends using multiple services and multiple ways. With filters you can have CocoaShare find files that matches the regular expression and automatically upload them. The screenshot filter will automatically upload any screenshot taken using Mac OS X's built screenshot system. Dragging files to the dock or menu bar icon will upload them at your request. After a file is uploaded, it places the URL in your clipboard so you can easily paste it into a message for your friends. Events allows you to set options for when a file is being uploaded and when a file is uploaded, such as displaying a growl notification or playing a sound to let you know when it's uploaded. By using CocoaShare, you'll find how easy it is to share files.\
\
Services Included:\
{\field{\*\fldinst{HYPERLINK "http://tinygrab.com/"}}{\fldrslt TinyGrab}}\
{\field{\*\fldinst{HYPERLINK "https://www.dropbox.com/"}}{\fldrslt Dropbox}}\
FTP - File Transfer Protocol.\
HTTP - Hypertext Transport Protocol (Using a custom PHP script).\
{\field{\*\fldinst{HYPERLINK "https://www.me.com/"}}{\fldrslt MobileMe}}\
SFTP - File Transfer over Secure Shell.\
{\field{\*\fldinst{HYPERLINK "https://twitpic.com/"}}{\fldrslt twitpic}}\
WebDav - Web-based Distributed Authoring and Versioning.\
\
CocoaShare is open source at {\field{\*\fldinst{HYPERLINK "http://opensource.mrgeckosmedia.com/"}}{\fldrslt http://opensource.mrgeckosmedia.com/}}.}

View File

@ -0,0 +1,19 @@
//
// MGMAddons.h
// CocoaShare
//
// Created by James on 1/22/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@interface NSString (MGMAddons)
- (NSString *)replace:(NSString *)targetString with:(NSString *)replaceString;
- (NSString *)escapePath;
@end
@interface NSBezierPath (MGMAddons)
+ (NSBezierPath *)pathWithRect:(NSRect)theRect radiusX:(float)theRadiusX radiusY:(float)theRadiusY;
- (void)fillGradientFrom:(NSColor *)theStartColor to:(NSColor *)theEndColor;
@end

View File

@ -0,0 +1,115 @@
//
// MGMAddons.m
// CocoaShare
//
// Created by James on 1/22/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMAddons.h"
#import <QuartzCore/QuartzCore.h>
@implementation NSString (MGMAddons)
- (NSString *)replace:(NSString *)targetString with:(NSString *)replaceString {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSMutableString *temp = [NSMutableString new];
NSRange replaceRange = NSMakeRange(0, [self length]);
NSRange rangeInOriginalString = replaceRange;
int replaced = 0;
while (1) {
NSRange rangeToCopy;
NSRange foundRange = [self rangeOfString:targetString options:0 range:rangeInOriginalString];
if (foundRange.length == 0) break;
rangeToCopy = NSMakeRange(rangeInOriginalString.location, foundRange.location - rangeInOriginalString.location);
[temp appendString:[self substringWithRange:rangeToCopy]];
[temp appendString:replaceString];
rangeInOriginalString.length -= NSMaxRange(foundRange) -
rangeInOriginalString.location;
rangeInOriginalString.location = NSMaxRange(foundRange);
replaced++;
if (replaced % 100 == 0) {
[pool drain];
pool = [NSAutoreleasePool new];
}
}
if (rangeInOriginalString.length > 0) [temp appendString:[self substringWithRange:rangeInOriginalString]];
[pool drain];
return [temp autorelease];
}
- (NSString *)escapePath {
NSString *escapedPath = [self replace:@" " with:@"\\ "];
escapedPath = [escapedPath replace:@"\"" with:@"\\\""];
escapedPath = [escapedPath replace:@"'" with:@"\\'"];
return escapedPath;
}
@end
@implementation NSBezierPath (MGMAddons)
+ (NSBezierPath *)pathWithRect:(NSRect)theRect radiusX:(float)theRadiusX radiusY:(float)theRadiusY {
NSBezierPath *path = [NSBezierPath bezierPath];
float maxRadiusX = theRect.size.width / 2.0;
float maxRadiusY = theRect.size.height / 2.0;
theRadiusX = (theRadiusX<maxRadiusX ? theRadiusX : maxRadiusX);
theRadiusY = (theRadiusY<maxRadiusY ? theRadiusY : maxRadiusY);
float ellipse = 0.55228474983079;
float controlX = theRadiusX * ellipse;
float controlY = theRadiusY * ellipse;
NSRect edges = NSInsetRect(theRect, theRadiusX, theRadiusY);
[path moveToPoint:NSMakePoint(edges.origin.x, theRect.origin.y)];
// top right corner
[path lineToPoint:NSMakePoint(NSMaxX(edges), theRect.origin.y)];
[path curveToPoint:NSMakePoint(NSMaxX(theRect), edges.origin.y) controlPoint1:NSMakePoint(NSMaxX(edges) + controlX, theRect.origin.y) controlPoint2:NSMakePoint(NSMaxX(theRect), edges.origin.y - controlY)];
// bottom right corner
[path lineToPoint:NSMakePoint(NSMaxX(theRect), NSMaxY(edges))];
[path curveToPoint:NSMakePoint(NSMaxX(edges), NSMaxY(theRect)) controlPoint1:NSMakePoint(NSMaxX(theRect), NSMaxY(edges) + controlY) controlPoint2:NSMakePoint(NSMaxX(edges) + controlX, NSMaxY(theRect))];
// bottom left corner
[path lineToPoint:NSMakePoint(edges.origin.x, NSMaxY(theRect))];
[path curveToPoint:NSMakePoint(theRect.origin.x, NSMaxY(edges)) controlPoint1:NSMakePoint(edges.origin.x - controlX, NSMaxY(theRect)) controlPoint2:NSMakePoint(theRect.origin.x, NSMaxY(edges) + controlY)];
// top left corner
[path lineToPoint:NSMakePoint(theRect.origin.x, edges.origin.y)];
[path curveToPoint:NSMakePoint(edges.origin.x, theRect.origin.y) controlPoint1:NSMakePoint(theRect.origin.x, edges.origin.y - controlY) controlPoint2:NSMakePoint(edges.origin.x - controlX, theRect.origin.y)];
[path closePath];
return path;
}
- (void)fillGradientFrom:(NSColor *)theStartColor to:(NSColor *)theEndColor {
CIFilter *filter = [CIFilter filterWithName:@"CILinearGradient"];
theStartColor = [theStartColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
theEndColor = [theEndColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
if (![[NSGraphicsContext currentContext] isFlipped]) {
NSColor *start = theStartColor;
NSColor *end = theEndColor;
theEndColor = start;
theStartColor = end;
}
CIColor *startColor = [CIColor colorWithRed:[theStartColor redComponent] green:[theStartColor greenComponent] blue:[theStartColor blueComponent] alpha:[theStartColor alphaComponent]];
CIColor *endColor = [CIColor colorWithRed:[theEndColor redComponent] green:[theEndColor greenComponent] blue:[theEndColor blueComponent] alpha:[theEndColor alphaComponent]];
[filter setValue:startColor forKey:@"inputColor0"];
[filter setValue:endColor forKey:@"inputColor1"];
CIVector *startVector = [CIVector vectorWithX:0.0 Y:0.0];
[filter setValue:startVector forKey:@"inputPoint0"];
CIVector *endVector = [CIVector vectorWithX:0.0 Y:[self bounds].size.height];
[filter setValue:endVector forKey:@"inputPoint1"];
CIImage *coreimage = [filter valueForKey:@"outputImage"];
[[NSGraphicsContext currentContext] saveGraphicsState];
[self setClip];
CIContext *context = [[NSGraphicsContext currentContext] CIContext];
[context drawImage:coreimage atPoint:CGPointMake([self bounds].origin.x, [self bounds].origin.y) fromRect:CGRectMake(0.0, 0.0, [self bounds].size.width, [self bounds].size.height)];
[[NSGraphicsContext currentContext] restoreGraphicsState];
}
@end

View File

@ -0,0 +1,15 @@
//
// MGMAutoUpdateField.h
// CocoaShare
//
// Created by James on 1/17/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@interface MGMAutoUpdateField : NSTextField {
}
@end

View File

@ -0,0 +1,15 @@
//
// MGMAutoUpdateField.m
// CocoaShare
//
// Created by James on 1/17/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMAutoUpdateField.h"
@implementation MGMAutoUpdateField
- (void)keyUp:(NSEvent *)theEvent {
[self sendAction:[self action] to:[self target]];
}
@end

View File

@ -0,0 +1,116 @@
//
// CocoaShareAppDelegate.h
// CocoaShare
//
// Created by Mr. Gecko on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
#import "MGMPlugInProtocol.h"
extern NSString * const MGMDisplay;
extern NSString * const MGMStartup;
extern NSString * const MGMUploadName;
extern NSString * const MGMHistoryCount;
extern NSString * const MGMGrowlErrors;
extern NSString * const MGMESound;
extern NSString * const MGMEPath;
extern NSString * const MGMEDelete;
extern NSString * const MGMEGrowl;
extern const int MGMEUploadingAutomatic;
extern const int MGMEUploadedAutomatic;
extern const int MGMEUploading;
extern const int MGMEUploaded;
extern NSString * const MGMEventNotification;
extern NSString * const MGMEvent;
extern NSString * const MGMEventPath;
extern NSString * const MGMEventURL;
extern NSString * const MGMFiltersPlist;
extern NSString * const MGMFPath;
extern NSString * const MGMFFilter;
@class MGMURLConnectionManager, MGMPreferences, MGMAbout, MGMMenuItem, MGMPathSubscriber;
@interface MGMController : NSObject {
MGMURLConnectionManager *connectionManager;
MGMPreferences *preferences;
MGMAbout *about;
ProcessSerialNumber lastFrontProcess;
IBOutlet NSMenu *mainMenu;
IBOutlet NSMenuItem *disableFilters;
MGMMenuItem *menuItem;
NSStatusItem *statusItem;
NSMutableArray *history;
NSMutableArray *filters;
NSLock *saveLock;
int saveCount;
MGMPathSubscriber *filterWatcher;
BOOL filtersEnabled;
NSMutableArray *accountPlugIns;
NSMutableArray *plugIns;
id<MGMPlugInProtocol> currentPlugIn;
int currentPlugInIndex;
NSMutableArray *uploads;
}
+ (id)sharedController;
- (void)registerDefaults;
- (MGMURLConnectionManager *)connectionManager;
- (MGMPreferences *)preferences;
- (void)loadPlugIns;
- (NSArray *)accountPlugIns;
- (NSArray *)plugIns;
- (void)setCurrentPlugIn:(id)thePlugIn;
- (id<MGMPlugInProtocol>)currentPlugIn;
- (int)currentPlugInIndex;
- (void)becomeFront:(NSWindow *)theWindow;
- (void)resignFront;
- (void)addMenu;
- (void)removeMenu;
- (void)setDockHidden:(BOOL)isHidden;
- (NSMutableArray *)history;
- (void)updateMenu;
- (void)addURLToHistory:(NSURL *)theURL;
- (IBAction)uploadFile:(id)sender;
- (IBAction)disableFilters:(id)sender;
- (IBAction)about:(id)sender;
- (IBAction)preferences:(id)sender;
- (IBAction)donate:(id)sender;
- (IBAction)quit:(id)sender;
- (NSMutableArray *)filters;
- (void)saveFilters;
- (MGMPathSubscriber *)filterWatcher;
- (NSArray *)filtersForPath:(NSString *)thePath;
- (void)updateFilterWatcher;
- (void)subscribedPathChanged:(NSString *)thePath;
- (void)removePassword;
- (void)setPassword:(NSString *)thePassword;
- (NSString *)password;
- (void)processEvent:(int)theEvent path:(NSString *)thePath;
- (void)processEvent:(int)theEvent path:(NSString *)thePath url:(NSURL *)theURL;
- (NSMutableArray *)uploads;
- (NSDictionary *)uploadForPath:(NSString *)thePath;
- (void)addPathToUploads:(NSString *)thePath isAutomatic:(BOOL)isAutomatic;
- (void)processNextUpload;
- (void)upload:(NSString *)thePath receivedError:(NSError *)theError;
- (void)uploadFinished:(NSString *)thePath url:(NSURL *)theURL;
@end

View File

@ -0,0 +1,684 @@
//
// MGMController.m
// CocoaShare
//
// Created by Mr. Gecko on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMController.h"
#import "MGMFileManager.h"
#import "MGMPathSubscriber.h"
#import "MGMLoginItems.h"
#import "MGMMenuItem.h"
#import "RegexKitLite.h"
#import <MGMUsers/MGMUsers.h>
#import <GeckoReporter/GeckoReporter.h>
#import <Growl/GrowlApplicationBridge.h>
NSString * const MGMCopyright = @"Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/";
NSString * const MGMVersion = @"MGMVersion";
NSString * const MGMLaunchCount = @"MGMLaunchCount";
NSString * const MGMDisplay = @"MGMDisplay";
NSString * const MGMStartup = @"MGMStartup";
NSString * const MGMUploadName = @"MGMUploadName";
NSString * const MGMHistoryCount = @"MGMHistoryCount";
NSString * const MGMGrowlErrors = @"MGMGrowlErrors";
NSString * const MGMHistoryPlist = @"history.plist";
NSString * const MGMHURL = @"url";
NSString * const MGMHDate = @"date";
NSString * const MGMESound = @"MGME%dSound";
NSString * const MGMEPath = @"MGME%dPath";
NSString * const MGMEDelete = @"MGME%dDelete";
NSString * const MGMEGrowl = @"MGME%dGrowl";
const int MGMEUploadingAutomatic = 0;
const int MGMEUploadedAutomatic = 1;
const int MGMEUploading = 2;
const int MGMEUploaded = 3;
NSString * const MGMEventNotification = @"MGMEventNotification";
NSString * const MGMEvent = @"event";
NSString * const MGMEventPath = @"path";
NSString * const MGMEventURL = @"URL";
NSString * const MGMFiltersPlist = @"filters.plist";
NSString * const MGMFPath = @"path";
NSString * const MGMFFilter = @"filter";
NSString * const MGMPluginFolder = @"PlugIns";
NSString * const MGMCurrentPlugIn = @"MGMCurrentPlugIn";
NSString * const MGMKCType = @"application password";
NSString * const MGMKCName = @"CocoaShare";
NSString * const MGMUPath = @"path";
NSString * const MGMUAutomatic = @"automatic";
NSString * const MGMNSStringPboardType = @"NSStringPboardType";
NSString * const MGMNSPasteboardTypeString = @"public.utf8-plain-text";
static MGMController *MGMSharedController;
@implementation MGMController
+ (id)sharedController {
if (MGMSharedController==nil) {
MGMSharedController = [MGMController new];
}
return MGMSharedController;
}
- (id)init {
if (MGMSharedController!=nil) {
if (self = [super init])
[self release];
self = MGMSharedController;
} else if (self = [super init]) {
MGMSharedController = self;
}
return self;
}
- (void)awakeFromNib {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setup) name:MGMGRDoneNotification object:nil];
[MGMReporter sharedReporter];
}
- (void)setup {
[GrowlApplicationBridge setGrowlDelegate:nil];
connectionManager = [[MGMURLConnectionManager managerWithCookieStorage:[MGMUser cookieStorage]] retain];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[self registerDefaults];
if ([defaults integerForKey:MGMLaunchCount]!=5) {
[defaults setInteger:[defaults integerForKey:MGMLaunchCount]+1 forKey:MGMLaunchCount];
if ([defaults integerForKey:MGMLaunchCount]==5) {
NSAlert *alert = [[NSAlert new] autorelease];
[alert setMessageText:@"Donations"];
[alert setInformativeText:@"Thank you for using CocoaShare. CocoaShare is donation supported software. If you like using it, please consider giving a donation to help with development."];
[alert addButtonWithTitle:@"Yes"];
[alert addButtonWithTitle:@"No"];
int result = [alert runModal];
if (result==1000)
[self donate:self];
}
}
if ([defaults boolForKey:MGMStartup])
[[MGMLoginItems items] addSelf];
NSFileManager *manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist]]) {
history = [[NSMutableArray arrayWithContentsOfFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist]] retain];
[self updateMenu];
} else {
history = [NSMutableArray new];
[history writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist] atomically:YES];
[self updateMenu];
}
saveLock = [NSLock new];
filterWatcher = [MGMPathSubscriber sharedPathSubscriber];
[filterWatcher setDelegate:self];
if ([manager fileExistsAtPath:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist]]) {
filters = [[NSMutableArray arrayWithContentsOfFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist]] retain];
[self updateFilterWatcher];
} else {
filters = [NSMutableArray new];
[self saveFilters];
}
filtersEnabled = YES;
if ([defaults integerForKey:MGMDisplay]>0)
[self addMenu];
preferences = [MGMPreferences new];
[preferences addPreferencesPaneClassName:@"MGMGeneralPane"];
[preferences addPreferencesPaneClassName:@"MGMAccountPane"];
[preferences addPreferencesPaneClassName:@"MGMAutoUploadPane"];
[preferences addPreferencesPaneClassName:@"MGMEventsPane"];
if ([defaults integerForKey:MGMLaunchCount]==2)
[preferences showPreferences];
about = [MGMAbout new];
uploads = [NSMutableArray new];
[self loadPlugIns];
}
- (void)dealloc {
[connectionManager release];
[preferences release];
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
[statusItem release];
[menuItem release];
[history release];
[filters release];
[saveLock release];
[filterWatcher release];
[accountPlugIns release];
[plugIns release];
[uploads release];
[super dealloc];
}
- (void)registerDefaults {
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
[defaults setObject:[[MGMSystemInfo info] applicationVersion] forKey:MGMVersion];
[defaults setObject:[NSNumber numberWithInt:1] forKey:MGMLaunchCount];
[defaults setObject:[NSNumber numberWithInt:([[MGMSystemInfo info] isUIElement] ? 2 : 0)] forKey:MGMDisplay];
[defaults setObject:[NSNumber numberWithBool:[[MGMLoginItems items] selfExists]] forKey:MGMStartup];
[defaults setObject:[NSNumber numberWithInt:0] forKey:MGMUploadName];
[defaults setObject:[NSNumber numberWithInt:5] forKey:MGMHistoryCount];
[defaults setObject:[NSNumber numberWithInt:2] forKey:[NSString stringWithFormat:MGMEDelete, MGMEUploadedAutomatic]];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
}
- (MGMURLConnectionManager *)connectionManager {
return connectionManager;
}
- (MGMPreferences *)preferences {
return preferences;
}
- (void)loadPlugIns {
NSFileManager *manager = [NSFileManager defaultManager];
[accountPlugIns release];
accountPlugIns = [NSMutableArray new];
[plugIns release];
plugIns = [NSMutableArray new];
NSArray *checkPaths = [NSArray arrayWithObjects:[[NSBundle mainBundle] builtInPlugInsPath], [[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMPluginFolder], nil];
for (int i=0; i<[checkPaths count]; i++) {
NSArray *plugInsFolder = [manager contentsOfDirectoryAtPath:[checkPaths objectAtIndex:i]];
for (int p=0; p<[plugInsFolder count]; p++) {
NSString *path = [[[checkPaths objectAtIndex:i] stringByAppendingPathComponent:[plugInsFolder objectAtIndex:p]] stringByResolvingSymlinksInPath];
NSBundle *bundle = [NSBundle bundleWithPath:path];
if (bundle!=nil) {
Class plugInClass = [bundle principalClass];
id<MGMPlugInProtocol> plugIn = [[[plugInClass alloc] init] autorelease];
if (plugIn!=nil && [plugIn respondsToSelector:@selector(isAccountPlugIn)] && [plugIn isAccountPlugIn])
[accountPlugIns addObject:plugIn];
else if (plugIn!=nil)
[plugIns addObject:plugIn];
}
}
}
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *currentPlugInName = [defaults objectForKey:MGMCurrentPlugIn];
BOOL foundCurrentPlugIn = NO;
for (int i=0; i<[accountPlugIns count]; i++) {
if ([NSStringFromClass([[accountPlugIns objectAtIndex:i] class]) isEqual:currentPlugInName]) {
currentPlugIn = [accountPlugIns objectAtIndex:i];
currentPlugInIndex = i;
if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:YES];
foundCurrentPlugIn = YES;
break;
}
}
if (!foundCurrentPlugIn && [accountPlugIns count]>0)
[self setCurrentPlugIn:[accountPlugIns objectAtIndex:0]];
}
- (NSArray *)accountPlugIns {
return accountPlugIns;
}
- (NSArray *)plugIns {
return plugIns;
}
- (void)setCurrentPlugIn:(id)thePlugIn {
int plugInIndex = [accountPlugIns indexOfObject:thePlugIn];
if (plugInIndex>=0) {
[self removePassword];
if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:NO];
currentPlugIn = thePlugIn;
currentPlugInIndex = plugInIndex;
[[NSUserDefaults standardUserDefaults] setObject:NSStringFromClass([currentPlugIn class]) forKey:MGMCurrentPlugIn];
if ([currentPlugIn respondsToSelector:@selector(setCurrentPlugIn:)]) [currentPlugIn setCurrentPlugIn:YES];
}
}
- (id<MGMPlugInProtocol>)currentPlugIn {
return currentPlugIn;
}
- (int)currentPlugInIndex {
return currentPlugInIndex;
}
- (void)becomeFront:(NSWindow *)theWindow {
GetFrontProcess(&lastFrontProcess);
if (theWindow!=nil) {
if ([[MGMSystemInfo info] isUIElement])
[theWindow setLevel:NSFloatingWindowLevel];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:theWindow];
}
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
}
- (void)resignFront {
SetFrontProcess(&lastFrontProcess);
}
- (void)windowWillClose:(NSNotification *)notification {
[[NSNotificationCenter defaultCenter] removeObserver:self name:[notification name] object:[notification object]];
[self resignFront];
}
- (void)addMenu {
if (statusItem==nil) {
menuItem = [[MGMMenuItem alloc] initWithFrame:NSZeroRect];
[menuItem setDelegate:self];
[menuItem setImage:[NSImage imageNamed:@"menuicon"]];
[menuItem setAlternateImage:[NSImage imageNamed:@"menuiconselected"]];
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];
[statusItem setView:menuItem];
[statusItem setToolTip:@"CocoaShare"];
}
}
- (void)removeMenu {
if (statusItem!=nil) {
[[NSStatusBar systemStatusBar] removeStatusItem:statusItem];
[statusItem release];
statusItem = nil;
[menuItem release];
menuItem = nil;
}
}
- (void)setDockHidden:(BOOL)isHidden {
NSFileManager *manager = [NSFileManager defaultManager];
NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [[bundle bundlePath] stringByAppendingPathComponent:@"Contents/Info.plist"];
if ([manager isWritableFileAtPath:path]) {
NSMutableDictionary *infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
[infoDict setObject:[NSNumber numberWithBool:isHidden] forKey:@"LSUIElement"];
[infoDict writeToFile:path atomically:NO];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate];
[manager setAttributes:attributes ofItemAtPath:[bundle bundlePath]];
if (isHidden) {
NSAlert *alert = [[NSAlert new] autorelease];
[alert setMessageText:@"Restart Required"];
[alert setInformativeText:@"Inorder to hide the dock, you must restart CocoaShare. Do you want to restart CocoaShare now?"];
[alert addButtonWithTitle:@"Yes"];
[alert addButtonWithTitle:@"No"];
int result = [alert runModal];
if (result==1000) {
//Took from Sparkle.
NSString *pathToRelaunch = [[NSBundle mainBundle] bundlePath];
NSString *relaunchPath = [[[NSBundle bundleWithIdentifier:@"org.andymatuschak.Sparkle"] resourcePath] stringByAppendingPathComponent:@"relaunch"];
[NSTask launchedTaskWithLaunchPath:relaunchPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], nil]];
[[NSApplication sharedApplication] terminate:self];
}
}
} else {
NSAlert *alert = [[NSAlert new] autorelease];
[alert setMessageText:@"Unable to change dock"];
[alert setInformativeText:[NSString stringWithFormat:@"CocoaShare is unable to %@ the dock due to permissions. To fix this issue, right click on CocoaShare and choose Get Info to make CocoaShare writable.", (isHidden ? @"hide" : @"unhide")]];
[alert runModal];
}
if (!isHidden) {
ProcessSerialNumber psn = {0, kCurrentProcess};
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
[self resignFront];
[self performSelector:@selector(becomeFront:) withObject:[preferences preferencesWindow] afterDelay:0.0];
}
}
- (void)menuClicked:(id)sender {
[statusItem popUpStatusItemMenu:mainMenu];
}
- (void)menuDraggingEntered:(id)sender {
[menuItem setImage:[NSImage imageNamed:@"menuicondrag"]];
}
- (void)menuDraggingExited:(id)sender {
[menuItem setImage:[NSImage imageNamed:@"menuicon"]];
}
- (void)menu:(id)sender droppedFiles:(NSArray *)files {
NSFileManager *manager = [NSFileManager defaultManager];
for (int i=0; i<[files count]; i++) {
BOOL directory = NO;
if ([manager fileExistsAtPath:[files objectAtIndex:i] isDirectory:&directory]) {
if (directory) {
NSAlert *alert = [[NSAlert new] autorelease];
[alert setMessageText:@"Upload Error"];
[alert setInformativeText:@"Uploading of directories is impossible."];
[alert runModal];
continue;
}
[self addPathToUploads:[files objectAtIndex:i] isAutomatic:NO];
}
}
}
- (NSMutableArray *)history {
return history;
}
- (void)updateMenu {
int splitterIndex = 0;
for (int i=0; i<[mainMenu numberOfItems]; i++) {
if ([[mainMenu itemAtIndex:i] isSeparatorItem]) {
splitterIndex = i;
break;
}
[mainMenu removeItemAtIndex:i];
i--;
}
if ([history count]>0) {
for (int i=0; i<[history count]; i++) {
NSDictionary *historyItem = [history objectAtIndex:i];
NSMenuItem *item = [[NSMenuItem new] autorelease];
NSDateFormatter *formatter = [[NSDateFormatter new] autorelease];
[formatter setDateFormat:@"MMMM d, yyyy h:mm:ss a"];
[item setTitle:[formatter stringFromDate:[historyItem objectForKey:MGMHDate]]];
[item setRepresentedObject:[historyItem objectForKey:MGMHURL]];
[item setTarget:self];
[item setAction:@selector(copyHistoryItem:)];
[mainMenu insertItem:item atIndex:splitterIndex];
}
} else {
NSMenuItem *item = [[NSMenuItem new] autorelease];
[item setTitle:@"No Upload History"];
[item setEnabled:NO];
[mainMenu insertItem:item atIndex:splitterIndex];
}
}
- (IBAction)copyHistoryItem:(id)sender {
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
[pboard declareTypes:[NSArray arrayWithObjects:MGMNSStringPboardType, MGMNSPasteboardTypeString, nil] owner:nil];
[pboard setString:[sender representedObject] forType:MGMNSStringPboardType];
[pboard setString:[sender representedObject] forType:MGMNSPasteboardTypeString];
}
- (void)addURLToHistory:(NSURL *)theURL {
[history addObject:[NSDictionary dictionaryWithObjectsAndKeys:[theURL absoluteString], MGMHURL, [NSDate date], MGMHDate, nil]];
int maxHistoryItems = [[NSUserDefaults standardUserDefaults] integerForKey:MGMHistoryCount];
int itemsToDelete = [history count]-maxHistoryItems;
if (itemsToDelete>0) {
for (int i=0; i<itemsToDelete; i++) {
[history removeObjectAtIndex:0];
}
}
[history writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMHistoryPlist] atomically:YES];
[self updateMenu];
}
- (IBAction)uploadFile:(id)sender {
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setCanChooseFiles:YES];
[panel setCanChooseDirectories:NO];
[panel setResolvesAliases:YES];
[panel setAllowsMultipleSelection:YES];
[panel setTitle:@"Choose File(s)"];
[panel setPrompt:@"Choose"];
[self becomeFront:nil];
int returnCode = [panel runModal];
if (returnCode==NSOKButton) {
for (int i=0; i<[[panel URLs] count]; i++) {
[self addPathToUploads:[[[panel URLs] objectAtIndex:i] path] isAutomatic:NO];
}
}
[self resignFront];
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag {
if (!flag)
[self preferences:self];
return YES;
}
- (void)application:(NSApplication *)theApplication openFiles:(NSArray *)theFiles {
for (int i=0; i<[theFiles count]; i++) {
[self addPathToUploads:[theFiles objectAtIndex:i] isAutomatic:NO];
}
}
- (IBAction)disableFilters:(id)sender {
filtersEnabled = !filtersEnabled;
[disableFilters setTitle:(filtersEnabled ? @"Disable Auto Upload" : @"Enable Auto Upload")];
}
- (IBAction)about:(id)sender {
[about show];
[self becomeFront:[about window]];
}
- (IBAction)preferences:(id)sender {
[preferences showPreferences];
[self becomeFront:[preferences preferencesWindow]];
}
- (IBAction)donate:(id)sender {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=U9LTDN57NPZ44"]];
}
- (IBAction)quit:(id)sender {
[[MGMLoginItems items] removeSelf];
[[NSApplication sharedApplication] terminate:self];
}
- (NSMutableArray *)filters {
return filters;
}
- (void)saveFilters {
if (saveCount==2)
return;
saveCount++;
NSAutoreleasePool *pool = [NSAutoreleasePool new];
[saveLock lock];
[filters writeToFile:[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMFiltersPlist] atomically:YES];
[self updateFilterWatcher];
saveCount--;
[pool drain];
[saveLock unlock];
}
- (MGMPathSubscriber *)filterWatcher {
return filterWatcher;
}
- (NSArray *)filtersForPath:(NSString *)thePath {
NSMutableArray *filtersFound = [NSMutableArray array];
for (int i=0; i<[filters count]; i++) {
NSString *path = [[[filters objectAtIndex:i] objectForKey:MGMFPath] stringByExpandingTildeInPath];
if ([path isEqual:thePath])
[filtersFound addObject:[filters objectAtIndex:i]];
}
return filtersFound;
}
- (void)updateFilterWatcher {
[filterWatcher removeAllPaths];
for (int i=0; i<[filters count]; i++) {
NSDictionary *filter = [filters objectAtIndex:i];
if (![[filter objectForKey:MGMFFilter] isEqual:@""]) {
NSString *path = [[filter objectForKey:MGMFPath] stringByExpandingTildeInPath];
if (![path isEqual:@""])
[filterWatcher addPath:path];
}
}
}
- (void)subscribedPathChanged:(NSString *)thePath {
if (filtersEnabled) {
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *filtersFound = [self filtersForPath:thePath];
NSArray *files = [manager contentsOfDirectoryAtPath:thePath];
for (int i=0; i<[files count]; i++) {
NSString *file = [files objectAtIndex:i];
NSString *fullPath = [thePath stringByAppendingPathComponent:file];
BOOL directory = NO;
if ([manager fileExistsAtPath:fullPath isDirectory:&directory] && !directory) {
for (int f=0; f<[filtersFound count]; f++) {
if ([file isMatchedByRegex:[[filtersFound objectAtIndex:f] objectForKey:MGMFFilter]])
[self addPathToUploads:fullPath isAutomatic:YES];
}
}
}
}
}
- (void)removePassword {
NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
if ([items count]>0)
[[items objectAtIndex:0] remove];
}
- (void)setPassword:(NSString *)thePassword {
NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
if ([items count]>0) {
[[items objectAtIndex:0] setString:thePassword];
} else {
[MGMKeychain addItem:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName password:thePassword];
}
}
- (NSString *)password {
NSArray *items = [MGMKeychain items:MGMKCType withName:MGMKCName service:MGMKCName account:MGMKCName];
if ([items count]>0)
return [[items objectAtIndex:0] string];
return nil;
}
- (void)processEvent:(int)theEvent path:(NSString *)thePath {
[self processEvent:theEvent path:thePath url:nil];
}
- (void)processEvent:(int)theEvent path:(NSString *)thePath url:(NSURL *)theURL {
NSMutableDictionary *eventInfo = [NSMutableDictionary dictionary];
[eventInfo setObject:[NSNumber numberWithInt:theEvent] forKey:MGMEvent];
[eventInfo setObject:thePath forKey:MGMEventPath];
if (theURL!=nil)
[eventInfo setObject:theURL forKey:MGMEventURL];
[[NSNotificationCenter defaultCenter] postNotificationName:MGMEventNotification object:self userInfo:eventInfo];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSFileManager *manager = [NSFileManager defaultManager];
NSString *soundPath = [defaults objectForKey:[NSString stringWithFormat:MGMESound, theEvent]];
if (soundPath!=nil && [manager fileExistsAtPath:soundPath]) {
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:soundPath byReference:YES];
[sound setDelegate:self];
[sound play];
}
NSString *path = [[defaults objectForKey:[NSString stringWithFormat:MGMEPath, theEvent]] stringByExpandingTildeInPath];
if ([manager fileExistsAtPath:path])
[manager moveItemAtPath:thePath toPath:path];
int deleteFile = [[defaults objectForKey:[NSString stringWithFormat:MGMEDelete, theEvent]] intValue];
if (deleteFile!=0 && [manager fileExistsAtPath:thePath]) {
if (deleteFile==1) {
[manager removeItemAtPath:thePath];
} else if (deleteFile==2) {
NSString *trash = [@"~/.Trash" stringByExpandingTildeInPath];
NSInteger tag;
[[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[thePath stringByDeletingLastPathComponent] destination:trash files:[NSArray arrayWithObject:[thePath lastPathComponent]] tag:&tag];
if (tag!=0)
NSLog(@"Error Deleting: %d", tag);
}
}
BOOL growl = [[defaults objectForKey:[NSString stringWithFormat:MGMEGrowl, theEvent]] boolValue];
if (growl) {
NSString *title = nil;
NSString *description = nil;
NSString *notificationName = nil;
if (theEvent==MGMEUploading) {
title = @"Uploading File";
description = [NSString stringWithFormat:@"Uploading %@", [[thePath lastPathComponent] stringByDeletingPathExtension]];
notificationName = @"UploadingFile";
} else if (theEvent==MGMEUploadingAutomatic) {
title = @"Automatically Uploading File";
description = [NSString stringWithFormat:@"Uploading %@", [[thePath lastPathComponent] stringByDeletingPathExtension]];
notificationName = @"UploadingFileAutomatically";
} else if (theEvent==MGMEUploaded) {
title = @"Uploaded File";
description = [NSString stringWithFormat:@"Uploaded %@ to %@", [[thePath lastPathComponent] stringByDeletingPathExtension], theURL];
notificationName = @"UploadedFile";
} else if (theEvent==MGMEUploadedAutomatic) {
title = @"Automatically Uploaded File";
description = [NSString stringWithFormat:@"Uploaded %@ to %@", [[thePath lastPathComponent] stringByDeletingPathExtension], theURL];
notificationName = @"UploadedFileAutomatically";
}
[GrowlApplicationBridge notifyWithTitle:title description:description notificationName:notificationName iconData:[[[NSApplication sharedApplication] applicationIconImage] TIFFRepresentation] priority:0 isSticky:NO clickContext:nil];
}
}
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finishedPlaying {
if (finishedPlaying)
[sound release];
}
- (NSMutableArray *)uploads {
return uploads;
}
- (NSDictionary *)uploadForPath:(NSString *)thePath {
for (int i=0; i<[uploads count]; i++) {
if ([[[uploads objectAtIndex:i] objectForKey:MGMUPath] isEqual:thePath])
return [uploads objectAtIndex:i];
}
return nil;
}
- (void)addPathToUploads:(NSString *)thePath isAutomatic:(BOOL)isAutomatic {
if ([self uploadForPath:thePath]==nil) {
if ([currentPlugIn respondsToSelector:@selector(allowedExtensions)]) {
if (![[currentPlugIn allowedExtensions] containsObject:[[thePath pathExtension] lowercaseString]]) {
NSAlert *alert = [[NSAlert new] autorelease];
[alert setMessageText:@"Upload Error"];
[alert setInformativeText:@"The current PlugIn does not support this file format."];
[alert runModal];
return;
}
}
[uploads addObject:[NSDictionary dictionaryWithObjectsAndKeys:thePath, MGMUPath, [NSNumber numberWithBool:isAutomatic], MGMUAutomatic, nil]];
if ([uploads count]==1)
[self processNextUpload];
}
}
- (void)processNextUpload {
if ([uploads count]>0) {
if (currentPlugIn==nil) {
NSAlert *alert = [[NSAlert new] autorelease];
[alert setMessageText:@"Upload Error"];
[alert setInformativeText:@"No PlugIns found. You must have at least 1 PlugIn to upload a file."];
[alert runModal];
[uploads removeAllObjects];
return;
} else if (![currentPlugIn respondsToSelector:@selector(sendFileAtPath:withName:)]) {
NSAlert *alert = [[NSAlert new] autorelease];
[alert setMessageText:@"Upload Error"];
[alert setInformativeText:@"The current PlugIn doesn't support uploading."];
[alert runModal];
[uploads removeAllObjects];
return;
}
NSFileManager *manager = [NSFileManager defaultManager];
NSDictionary *upload = [uploads objectAtIndex:0];
if (![manager fileExistsAtPath:[upload objectForKey:MGMUPath]]) {
[uploads removeObject:upload];
[self processNextUpload];
return;
}
[menuItem setImage:[NSImage imageNamed:@"menuiconupload"]];
[self processEvent:([[upload objectForKey:MGMUAutomatic] boolValue] ? MGMEUploadingAutomatic : MGMEUploading) path:[upload objectForKey:MGMUPath]];
int uploadNameType = [[[NSUserDefaults standardUserDefaults] objectForKey:MGMUploadName] intValue];
NSString *randomizedName = [[NSString stringWithFormat:@"%d", [[NSDate date] timeIntervalSince1970]] MD5];
NSString *name = [[upload objectForKey:MGMUPath] lastPathComponent];
if ((uploadNameType==0 && [[upload objectForKey:MGMUAutomatic] boolValue]) || uploadNameType==1)
name = [randomizedName stringByAppendingPathExtension:[name pathExtension]];
[currentPlugIn sendFileAtPath:[upload objectForKey:MGMUPath] withName:name];
} else {
[menuItem setImage:[NSImage imageNamed:@"menuicon"]];
}
}
- (void)upload:(NSString *)thePath receivedError:(NSError *)theError {
NSDictionary *upload = [self uploadForPath:thePath];
if (upload!=nil) {
if ([[NSUserDefaults standardUserDefaults] boolForKey:MGMGrowlErrors]) {
[GrowlApplicationBridge notifyWithTitle:@"Unable to upload" description:[NSString stringWithFormat:@"%@: %@", [[upload objectForKey:MGMUPath] lastPathComponent], [theError localizedDescription]] notificationName:@"UploadError" iconData:[[[NSApplication sharedApplication] applicationIconImage] TIFFRepresentation] priority:1 isSticky:NO clickContext:nil];
} else {
NSAlert *alert = [[NSAlert new] autorelease];
[alert setMessageText:@"Upload Error"];
[alert setInformativeText:[NSString stringWithFormat:@"Unable to upload %@: %@", [[upload objectForKey:MGMUPath] lastPathComponent], [theError localizedDescription]]];
[alert runModal];
}
[uploads removeObject:upload];
[self processNextUpload];
}
}
- (void)uploadFinished:(NSString *)thePath url:(NSURL *)theURL {
NSDictionary *upload = [self uploadForPath:thePath];
if (upload!=nil) {
[self processEvent:([[upload objectForKey:MGMUAutomatic] boolValue] ? MGMEUploadedAutomatic : MGMEUploaded) path:[upload objectForKey:MGMUPath] url:theURL];
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
[pboard declareTypes:[NSArray arrayWithObjects:MGMNSStringPboardType, MGMNSPasteboardTypeString, nil] owner:nil];
[pboard setString:[theURL absoluteString] forType:MGMNSStringPboardType];
[pboard setString:[theURL absoluteString] forType:MGMNSPasteboardTypeString];
[self addURLToHistory:theURL];
[uploads removeObject:upload];
[self processNextUpload];
}
}
@end

View File

@ -0,0 +1,22 @@
//
// MGMFileManager.h
// CocoaShare
//
// Created by James on 1/22/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@interface NSFileManager (MGMFileManager)
- (BOOL)moveItemAtPath:(NSString *)thePath toPath:(NSString *)theDestination;
- (BOOL)copyItemAtPath:(NSString *)thePath toPath:(NSString *)theDestination;
- (BOOL)removeItemAtPath:(NSString *)thePath;
- (BOOL)linkItemAtPath:(NSString *)thePath toPath:(NSString *)theDestination;
- (BOOL)createSymbolicLinkAtPath:(NSString *)thePath withDestinationPath:(NSString *)theDestination;
- (NSString *)destinationOfSymbolicLinkAtPath:(NSString *)thePath;
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)thePath;
- (NSDictionary *)attributesOfFileSystemForPath:(NSString *)thePath;
- (void)setAttributes:(NSDictionary *)theAttributes ofItemAtPath:(NSString *)thePath;
- (NSDictionary *)attributesOfItemAtPath:(NSString *)thePath;
@end

View File

@ -0,0 +1,73 @@
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
//
// MGMFileManager.m
// CocoaShare
//
// Created by James on 1/22/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMFileManager.h"
@implementation NSFileManager (MGMFileManager)
- (BOOL)moveItemAtPath:(NSString *)thePath toPath:(NSString *)theDestination {
if ([self respondsToSelector:@selector(movePath:toPath:handler:)])
return [self movePath:thePath toPath:theDestination handler:nil];
else
return [self moveItemAtPath:thePath toPath:theDestination error:nil];
}
- (BOOL)copyItemAtPath:(NSString *)thePath toPath:(NSString *)theDestination {
if ([self respondsToSelector:@selector(copyPath:toPath:handler:)])
return [self copyPath:thePath toPath:theDestination handler:nil];
else
return [self copyItemAtPath:thePath toPath:theDestination error:nil];
}
- (BOOL)removeItemAtPath:(NSString *)thePath {
if ([self respondsToSelector:@selector(removeFileAtPath:handler:)])
return [self removeFileAtPath:thePath handler:nil];
else
return [self removeItemAtPath:thePath error:nil];
}
- (BOOL)linkItemAtPath:(NSString *)thePath toPath:(NSString *)theDestination {
if ([self respondsToSelector:@selector(linkPath:toPath:handler:)])
return [self linkPath:thePath toPath:theDestination handler:nil];
else
return [self linkItemAtPath:thePath toPath:theDestination error:nil];
}
- (BOOL)createSymbolicLinkAtPath:(NSString *)thePath withDestinationPath:(NSString *)theDestination {
if ([self respondsToSelector:@selector(createSymbolicLinkAtPath:pathContent:)])
return [self createSymbolicLinkAtPath:thePath pathContent:theDestination];
else
return [self createSymbolicLinkAtPath:thePath withDestinationPath:theDestination error:nil];
}
- (NSString *)destinationOfSymbolicLinkAtPath:(NSString *)thePath {
if ([self respondsToSelector:@selector(pathContentOfSymbolicLinkAtPath:)])
return [self pathContentOfSymbolicLinkAtPath:thePath];
else
return [self destinationOfSymbolicLinkAtPath:thePath error:nil];
}
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)thePath {
if ([self respondsToSelector:@selector(directoryContentsAtPath:)])
return [self directoryContentsAtPath:thePath];
else
return [self contentsOfDirectoryAtPath:thePath error:nil];
}
- (NSDictionary *)attributesOfFileSystemForPath:(NSString *)thePath {
if ([self respondsToSelector:@selector(fileSystemAttributesAtPath:)])
return [self fileSystemAttributesAtPath:thePath];
else
return [self attributesOfFileSystemForPath:thePath error:nil];
}
- (void)setAttributes:(NSDictionary *)theAttributes ofItemAtPath:(NSString *)thePath {
if ([self respondsToSelector:@selector(changeFileAttributes:atPath:)])
[self changeFileAttributes:theAttributes atPath:thePath];
else
[self setAttributes:theAttributes ofItemAtPath:thePath error:nil];
}
- (NSDictionary *)attributesOfItemAtPath:(NSString *)thePath {
if ([self respondsToSelector:@selector(fileAttributesAtPath:traverseLink:)])
return [self fileAttributesAtPath:thePath traverseLink:YES];
else
return [self attributesOfItemAtPath:thePath error:nil];
}
@end

View File

@ -0,0 +1,24 @@
//
// MGMLoginItems.h
// Exhaust
//
// Created by Mr. Gecko on 8/7/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@interface MGMLoginItems : NSObject {
NSMutableDictionary *loginItems;
}
+ (id)items;
- (NSArray *)paths;
- (BOOL)selfExists;
- (BOOL)addSelf;
- (BOOL)removeSelf;
- (BOOL)exists:(NSString *)thePath;
- (BOOL)add:(NSString *)thePath;
- (BOOL)add:(NSString *)thePath hide:(BOOL)shouldHide;
- (BOOL)remove:(NSString *)thePath;
- (void)_save;
@end

View File

@ -0,0 +1,89 @@
//
// MGMLoginItems.m
// Exhaust
//
// Created by Mr. Gecko on 8/7/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMLoginItems.h"
NSString * const MGMLoginItemsPath = @"~/Library/Preferences/loginwindow.plist";
NSString * const MGMItemsKey = @"AutoLaunchedApplicationDictionary";
NSString * const MGMPathKey = @"Path";
NSString * const MGMHideKey = @"Hide";
@implementation MGMLoginItems
+ (id)items {
return [[[self alloc] init] autorelease];
}
- (id)init {
if (self = [super init]) {
loginItems = [[NSMutableDictionary dictionaryWithContentsOfFile:[MGMLoginItemsPath stringByExpandingTildeInPath]] retain];
}
return self;
}
- (void)dealloc {
[loginItems release];
[super dealloc];
}
- (NSArray *)paths {
NSMutableArray *returnApps = [NSMutableArray array];
NSArray *applications = [loginItems objectForKey:MGMItemsKey];
for (int i=0; i<[applications count]; i++) {
[returnApps addObject:[[applications objectAtIndex:i] objectForKey:MGMPathKey]];
}
return returnApps;
}
- (BOOL)selfExists {
return [self exists:[[NSBundle mainBundle] bundlePath]];
}
- (BOOL)addSelf {
return [self add:[[NSBundle mainBundle] bundlePath]];
}
- (BOOL)removeSelf {
return [self remove:[[NSBundle mainBundle] bundlePath]];
}
- (BOOL)exists:(NSString *)thePath {
NSArray *applications = [loginItems objectForKey:MGMItemsKey];
for (int i=0; i<[applications count]; i++) {
if ([[[applications objectAtIndex:i] objectForKey:MGMPathKey] isEqual:thePath])
return YES;
}
return NO;
}
- (BOOL)add:(NSString *)thePath {
return [self add:thePath hide:NO];
}
- (BOOL)add:(NSString *)thePath hide:(BOOL)shouldHide {
if ([self exists:thePath])
return NO;
NSMutableArray *applications = [NSMutableArray arrayWithArray:[loginItems objectForKey:MGMItemsKey]];
NSMutableDictionary *info = [NSMutableDictionary dictionary];
[info setObject:thePath forKey:MGMPathKey];
[info setObject:[NSNumber numberWithBool:shouldHide] forKey:MGMHideKey];
[applications addObject:info];
[loginItems setObject:applications forKey:MGMItemsKey];
[self _save];
return YES;
}
- (BOOL)remove:(NSString *)thePath {
NSMutableArray *applications = [NSMutableArray arrayWithArray:[loginItems objectForKey:MGMItemsKey]];
for (int i=0; i<[applications count]; i++) {
if ([[[applications objectAtIndex:i] objectForKey:MGMPathKey] isEqual:thePath]) {
[applications removeObjectAtIndex:i];
[loginItems setObject:applications forKey:MGMItemsKey];
[self _save];
return YES;
}
}
return NO;
}
- (void)_save {
[loginItems writeToFile:[MGMLoginItemsPath stringByExpandingTildeInPath] atomically:YES];
}
@end

View File

@ -0,0 +1,33 @@
//
// MGMMenuItem.h
// CocoaShare
//
// Created by James on 1/16/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@protocol MGMMenuItemDelegate <NSObject>
- (void)menuClicked:(id)sender;
- (void)menuDraggingEntered:(id)sender;
- (void)menuDraggingExited:(id)sender;
- (void)menu:(id)sender droppedFiles:(NSArray *)files;
@end
@interface MGMMenuItem : NSView {
id<MGMMenuItemDelegate> delegate;
NSImage *image;
NSImage *alternateImage;
BOOL isHighlighted;
}
- (void)setDelegate:(id)theDelegate;
- (id<MGMMenuItemDelegate>)delegate;
- (void)setImage:(NSImage *)theImage;
- (NSImage *)image;
- (void)setAlternateImage:(NSImage *)theImage;
- (NSImage *)alternateImage;
@end

View File

@ -0,0 +1,87 @@
//
// MGMMenuItem.m
// CocoaShare
//
// Created by James on 1/16/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMMenuItem.h"
@implementation MGMMenuItem
- (id)initWithFrame:(NSRect)frame {
if ((self = [super initWithFrame:NSMakeRect(0, 0, 22, 22)])) {
[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
}
return self;
}
- (void)dealloc {
[image release];
[alternateImage release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MGMMenuItemDelegate>)delegate {
return delegate;
}
- (void)setImage:(NSImage *)theImage {
[image release];
image = [theImage copy];
[self display];
}
- (NSImage *)image {
return image;
}
- (void)setAlternateImage:(NSImage *)theImage {
[alternateImage release];
alternateImage = [theImage copy];
}
- (NSImage *)alternateImage {
return alternateImage;
}
- (void)drawRect:(NSRect)theRect {
NSImage *displayImage = image;
if (isHighlighted) {
NSBezierPath *path = [NSBezierPath bezierPathWithRect:theRect];
[[NSColor selectedMenuItemColor] set];
[path fill];
displayImage = alternateImage;
}
[displayImage drawInRect:NSMakeRect((22-[image size].width)/2, (22-[image size].height)/2, [image size].width, [image size].height) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}
- (void)mouseDown:(NSEvent *)theEvent {
isHighlighted = YES;
[self display];
if ([delegate respondsToSelector:@selector(menuClicked:)]) [delegate menuClicked:self];
isHighlighted = NO;
[self display];
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
if ([[[sender draggingPasteboard] types] containsObject:NSFilenamesPboardType]) {
if ([delegate respondsToSelector:@selector(menuDraggingEntered:)]) [delegate menuDraggingEntered:self];
return NSDragOperationEvery;
}
return NSDragOperationNone;
}
- (void)draggingExited:(id <NSDraggingInfo>)sender {
if ([delegate respondsToSelector:@selector(menuDraggingExited:)]) [delegate menuDraggingExited:self];
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
NSPasteboard *pboard = [sender draggingPasteboard];
if ([delegate respondsToSelector:@selector(menuDraggingExited:)]) [delegate menuDraggingExited:self];
if ([[pboard types] containsObject:NSFilenamesPboardType]) {
NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
if ([delegate respondsToSelector:@selector(menu:droppedFiles:)]) [delegate menu:self droppedFiles:files];
return YES;
}
return NO;
}
@end

View File

@ -0,0 +1,33 @@
//
// MGMPathSubscriber.h
// CocoaShare
//
// Created by Mr. Gecko on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Foundation/Foundation.h>
extern NSString * const MGMPathSubscriptionChangedNotification;
@protocol MGMPathSubscriberDelegate <NSObject>
- (void)subscribedPathChanged:(NSString *)thePath;
@end
@interface MGMPathSubscriber : NSObject {
id<MGMPathSubscriberDelegate> delegate;
NSMutableDictionary *subscriptions;
FNSubscriptionUPP subscriptionUPP;
NSMutableArray *notificationsSending;
}
+ (id)sharedPathSubscriber;
- (id<MGMPathSubscriberDelegate>)delegate;
- (void)setDelegate:(id)theDelegate;
- (void)addPath:(NSString *)thePath;
- (void)removePath:(NSString *)thePath;
- (void)removeAllPaths;
- (NSArray *)subscribedPaths;
@end

View File

@ -0,0 +1,101 @@
//
// MGMPathSubscriber.m
// CocoaShare
//
// Created by Mr. Gecko on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMPathSubscriber.h"
@interface MGMPathSubscriber (MGMPrivate)
- (void)subscriptionChanged:(FNSubscriptionRef)theSubscription;
- (void)sendNotificationForPath:(NSString *)thePath;
@end
static MGMPathSubscriber *MGMSharedPathSubscriber;
NSString * const MGMSubscribedPathChangedNotification = @"MGMSubscribedPathChangedNotification";
void MGMPathSubscriptionChange(FNMessage theMessage, OptionBits theFlags, void *thePathSubscription, FNSubscriptionRef theSubscription) {
if (theMessage==kFNDirectoryModifiedMessage)
[(MGMPathSubscriber *)thePathSubscription subscriptionChanged:theSubscription];
else
NSLog(@"MGMPathSubscription: Received unkown message: %d", theMessage);
}
@implementation MGMPathSubscriber
+ (id)sharedPathSubscriber {
if (MGMSharedPathSubscriber==nil)
MGMSharedPathSubscriber = [MGMPathSubscriber new];
return MGMSharedPathSubscriber;
}
- (id)init {
if ((self = [super init])) {
subscriptions = [NSMutableDictionary new];
subscriptionUPP = NewFNSubscriptionUPP(MGMPathSubscriptionChange);
notificationsSending = [NSMutableArray new];
}
return self;
}
- (void)dealloc {
[self removeAllPaths];
DisposeFNSubscriptionUPP(subscriptionUPP);
[subscriptions release];
[notificationsSending release];
[super dealloc];
}
- (id<MGMPathSubscriberDelegate>)delegate {
return delegate;
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (void)addPath:(NSString *)thePath {
NSValue *value = [subscriptions objectForKey:thePath];
if (value!=nil)
return;
FNSubscriptionRef subscription = NULL;
OSStatus error = FNSubscribeByPath((UInt8 *)[thePath fileSystemRepresentation], subscriptionUPP, self, kFNNotifyInBackground, &subscription);
if (error!=noErr) {
NSLog(@"MGMPathSubscription: Unable to subscribe to %@ due to the error %d", thePath, error);
return;
}
[subscriptions setObject:[NSValue valueWithPointer:subscription] forKey:thePath];
}
- (void)removePath:(NSString *)thePath {
NSValue *value = [subscriptions objectForKey:thePath];
if (value!=nil) {
FNUnsubscribe([value pointerValue]);
[subscriptions removeObjectForKey:thePath];
}
}
- (void)removeAllPaths {
NSArray *keys = [subscriptions allKeys];
for (int i=0; i<[keys count]; i++) {
FNUnsubscribe([[subscriptions objectForKey:[keys objectAtIndex:i]] pointerValue]);
}
[subscriptions removeAllObjects];
}
- (NSArray *)subscribedPaths {
return [subscriptions allKeys];
}
- (void)subscriptionChanged:(FNSubscriptionRef)theSubscription {
NSArray *keys = [subscriptions allKeysForObject:[NSValue valueWithPointer:theSubscription]];
if ([keys count]>=1) {
NSString *path = [keys objectAtIndex:0];
if (![notificationsSending containsObject:path]) {
[notificationsSending addObject:path];
[self performSelector:@selector(sendNotificationForPath:) withObject:path afterDelay:0.5];
}
}
}
- (void)sendNotificationForPath:(NSString *)thePath {
[[NSNotificationCenter defaultCenter] postNotificationName:MGMSubscribedPathChangedNotification object:thePath];
if ([delegate respondsToSelector:@selector(subscribedPathChanged:)]) [delegate subscribedPathChanged:thePath];
[notificationsSending removeObject:thePath];
}
@end

View File

@ -0,0 +1,19 @@
//
// MGMPlugInProtocol.h
// CocoaShare
//
// Created by James on 1/18/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@protocol MGMPlugInProtocol <NSObject>
- (BOOL)isAccountPlugIn;
- (NSString *)plugInName;
- (NSView *)plugInView;
- (void)releaseView;
- (NSArray *)allowedExtensions;
- (void)setCurrentPlugIn:(BOOL)isCurrent;
- (void)sendFileAtPath:(NSString *)thePath withName:(NSString *)theName;
@end

View File

@ -0,0 +1,69 @@
//
// MGMWebDav.h
// CocoaShare
//
// Created by James on 1/28/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
#import "MGMWebDavAddons.h"
#import "MGMWebDavOptions.h"
#import "MGMWebDavPropFind.h"
#import "MGMWebDavPut.h"
#import "MGMWebDavGet.h"
#import "MGMWebDavDelete.h"
#import "MGMWebDavMkCol.h"
extern NSString * const MGMWebDavErrorDomain;
extern NSString * const MGMWebDavDepth;
extern NSString * const MGMWebDavContentType;
extern NSString * const MGMWebDavXMLType;
@class MGMWebDav;
@protocol MGMWebDavDelegate <NSObject>
- (void)webDav:(MGMWebDav *)theSender loginFailedWithError:(NSError *)theError;
- (void)webDavLoginSuccessful:(MGMWebDav *)theSender;
@end
@protocol MGMWebDavHandler <NSObject>
- (void)setWebDav:(MGMWebDav *)theWebDav;
- (void)setConnection:(NSURLConnection *)theConnection;
- (NSURLConnection *)connection;
- (void)setRequest:(NSMutableURLRequest *)theRequest;
- (NSMutableURLRequest *)request;
- (NSURLCredential *)credentailsForChallenge:(NSURLAuthenticationChallenge *)theChallenge;
- (void)uploaded:(unsigned long)theBytes totalBytes:(unsigned long)theTotalBytes totalBytesExpected:(unsigned long)theExpectedBytes;
- (NSURLRequest *)willSendRequest:(NSURLRequest *)theRequest redirectResponse:(NSHTTPURLResponse *)theResponse;
- (void)didReceiveResponse:(NSHTTPURLResponse *)theResponse;
- (void)didReceiveData:(NSData *)theData;
- (void)didFailWithError:(NSError *)theError;
- (void)didFinishLoading;
@end
@interface MGMWebDav : NSObject {
id<MGMWebDavDelegate> delegate;
NSURL *rootURL;
NSURLCredential *credentials;
//CFHTTPAuthenticationRef authentication;
NSMutableArray *handlers;
}
+ (id)webDav;
+ (id)webDavWithDelegate:(id)theDelegate;
- (id)initWithDelegate:(id)theDelegate;
- (void)setDelegate:(id)theDelegate;
- (id<MGMWebDavDelegate>)delegate;
- (void)setRootURL:(NSURL *)theURL;
- (NSURL *)rootURL;
- (void)setCredentials:(NSURLCredential *)theCredentials;
- (void)setUser:(NSString *)theUser password:(NSString *)thePassword;
- (NSURLCredential *)credentials;
- (void)addHandler:(id)theHandler;
- (void)cancelHandler:(id)theHandler;
- (void)cancelAll;
@end

View File

@ -0,0 +1,233 @@
//
// MGMWebDav.m
// CocoaShare
//
// Created by James on 1/28/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMWebDav.h"
NSString * const MGMWebDavErrorDomain = @"com.MrGeckosMedia.WebDav";
NSString * const MGMWebDavUA = @"WebDAVFS/1.2.7 MGMWebDav/0.1";
NSString * const MGMWebDavUserAgent = @"User-Agent";
NSString * const MGMWebDavContentType = @"Content-Type";
NSString * const MGMWebDavXMLType = @"text/xml";
@interface MGMWebDav (MGMPrivate)
- (id<MGMWebDavHandler>)handlerForConnection:(NSURLConnection *)theConnection;
- (CFHTTPMessageRef)httpMessageFromResponse:(NSHTTPURLResponse *)theResponse;
- (CFHTTPMessageRef)httpMessageFromRequest:(NSURLRequest *)theRequest;
@end
@implementation MGMWebDav
+ (id)webDav {
return [[[self alloc] init] autorelease];
}
- (id)init {
if ((self = [super init])) {
handlers = [NSMutableArray new];
}
return self;
}
+ (id)webDavWithDelegate:(id)theDelegate {
return [[[self alloc] initWithDelegate:theDelegate] autorelease];
}
- (id)initWithDelegate:(id)theDelegate {
if ((self = [self init])) {
delegate = theDelegate;
}
return self;
}
- (void)dealloc {
[rootURL release];
[credentials release];
[handlers release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MGMWebDavDelegate>)delegate {
return delegate;
}
- (void)setRootURL:(NSURL *)theURL {
[rootURL release];
rootURL = [theURL retain];
}
- (NSURL *)rootURL {
return rootURL;
}
- (void)setCredentials:(NSURLCredential *)theCredentials {
[credentials release];
credentials = [theCredentials retain];
}
- (void)setUser:(NSString *)theUser password:(NSString *)thePassword {
[self setCredentials:[NSURLCredential credentialWithUser:theUser password:thePassword persistence:NSURLCredentialPersistenceForSession]];
}
- (NSURLCredential *)credentials {
return credentials;
}
- (void)addHandler:(id)theHandler {
id<MGMWebDavHandler> handler = theHandler;
if ([handler respondsToSelector:@selector(setWebDav:)]) [handler setWebDav:self];
if ([handler respondsToSelector:@selector(request)]) {
[handlers addObject:handler];
NSMutableURLRequest *request = [handler request];
[request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
[request setValue:MGMWebDavUA forHTTPHeaderField:MGMWebDavUserAgent];
/*if (authentication!=NULL) {
CFHTTPMessageRef message = [self httpMessageFromRequest:request];
CFStreamError error;
CFHTTPMessageApplyCredentials(message, authentication, (CFStringRef)[credentials user], (CFStringRef)[credentials password], &error);
NSLog(@"%d", error.error);
CFStringRef value = CFHTTPMessageCopyHeaderFieldValue(message, CFSTR("Authorization"));
NSLog(@"%@", (NSString *)value);
if (value!=NULL)
CFRelease(value);
value = CFHTTPAuthenticationCopyRealm(authentication);
NSLog(@"%@", (NSString *)value);
if (value!=NULL)
CFRelease(value);
CFRelease(message);
}*/
if ([handler respondsToSelector:@selector(setConnection:)])
[handler setConnection:[NSURLConnection connectionWithRequest:request delegate:self]];
}
}
- (id<MGMWebDavHandler>)handlerForConnection:(NSURLConnection *)theConnection {
for (unsigned long i=0; i<[handlers count]; i++) {
id<MGMWebDavHandler> handler = [handlers objectAtIndex:i];
if ([handler respondsToSelector:@selector(connection)]) {
if ([handler connection]==theConnection)
return handler;
}
}
return nil;
}
- (void)cancelHandler:(id)theHandler {
id<MGMWebDavHandler> handler = theHandler;
if ([handler respondsToSelector:@selector(connection)])
[[handler connection] cancel];
[handlers removeObject:handler];
}
- (void)cancelAll {
while ([handlers count]>0) {
id<MGMWebDavHandler> handler = [handlers objectAtIndex:0];
if ([handler respondsToSelector:@selector(connection)])
[[handler connection] cancel];
[handlers removeObject:handler];
}
}
- (CFHTTPMessageRef)httpMessageFromResponse:(NSHTTPURLResponse *)theResponse {
CFHTTPMessageRef message = CFHTTPMessageCreateResponse(kCFAllocatorDefault, [theResponse statusCode], (CFStringRef)[NSHTTPURLResponse localizedStringForStatusCode:[theResponse statusCode]], kCFHTTPVersion1_1);
NSDictionary *headers = [theResponse allHeaderFields];
NSArray *keys = [headers allKeys];
for (int i=0; i<[keys count]; i++) {
CFHTTPMessageSetHeaderFieldValue(message, (CFStringRef)[keys objectAtIndex:i], (CFStringRef)[headers objectForKey:[keys objectAtIndex:i]]);
}
return message;
}
- (CFHTTPMessageRef)httpMessageFromRequest:(NSURLRequest *)theRequest {
CFHTTPMessageRef message = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)[theRequest HTTPMethod], (CFURLRef)[theRequest URL], kCFHTTPVersion1_1);
NSDictionary *headers = [theRequest allHTTPHeaderFields];
NSArray *keys = [headers allKeys];
for (int i=0; i<[keys count]; i++) {
CFHTTPMessageSetHeaderFieldValue(message, (CFStringRef)[keys objectAtIndex:i], (CFStringRef)[headers objectForKey:[keys objectAtIndex:i]]);
}
if ([theRequest HTTPBody]!=nil)
CFHTTPMessageSetBody(message, (CFDataRef)[theRequest HTTPBody]);
return message;
}
- (void)connection:(NSURLConnection *)theConnection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)theChallenge {
//NSHTTPURLResponse *response = (NSHTTPURLResponse *)[theChallenge failureResponse];
/*NSString *authRequest = [[(NSHTTPURLResponse *)[theChallenge failureResponse] allHeaderFields] objectForKey:@"Www-Authenticate"];
NSCharacterSet *whiteSpace = [NSCharacterSet whitespaceCharacterSet];
NSRange range = [authRequest rangeOfCharacterFromSet:whiteSpace];
NSString *authType = [authRequest substringToIndex:range.location];
NSArray *parametersArray = [[authRequest substringFromIndex:range.location+range.length] componentsSeparatedByString:@","];
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
NSCharacterSet *quote = [NSCharacterSet characterSetWithCharactersInString:@"\"'"];
for (int i=0; i<[parametersArray count]; i++) {
NSString *parameter = [[parametersArray objectAtIndex:i] stringByTrimmingCharactersInSet:whiteSpace];
NSRange range = [parameter rangeOfString:@"="];
if (range.location!=NSNotFound)
[parameters setObject:[[parameter substringFromIndex:range.location+range.length] stringByTrimmingCharactersInSet:quote] forKey:[[parameter substringToIndex:range.location] stringByTrimmingCharactersInSet:quote]];
}
NSLog(@"%@", authRequest);
NSLog(@"%@ %@", authType, parameters);*/
/*if (authentication!=NULL)
CFRelease(authentication);
CFHTTPMessageRef message = [self httpMessageFromResponse:response];
authentication = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, message);
NSLog(@"%p", authentication);
CFRelease(message);*/
id<MGMWebDavHandler> handler = [self handlerForConnection:theConnection];
if ([theChallenge previousFailureCount]<=1 && (credentials!=nil || [handler respondsToSelector:@selector(credentailsForChallenge:)])) {
if ([handler respondsToSelector:@selector(credentailsForChallenge:)]) {
[[theChallenge sender] useCredential:[handler credentailsForChallenge:theChallenge] forAuthenticationChallenge:theChallenge];
} else {
[[theChallenge sender] useCredential:credentials forAuthenticationChallenge:theChallenge];
}
return;
}
[[theChallenge sender] cancelAuthenticationChallenge:theChallenge];
}
- (void)connection:(NSURLConnection *)theConnection didSendBodyData:(NSInteger)theBytes totalBytesWritten:(NSInteger)theTotalBytes totalBytesExpectedToWrite:(NSInteger)theExpectedBytes {
id<MGMWebDavHandler> handler = [self handlerForConnection:theConnection];
if ([handler respondsToSelector:@selector(uploaded:totalBytes:totalBytesExpected:)])
[handler uploaded:theBytes totalBytes:theTotalBytes totalBytesExpected:theExpectedBytes];
}
- (NSURLRequest *)connection:(NSURLConnection *)theConnection willSendRequest:(NSURLRequest *)theRequest redirectResponse:(NSHTTPURLResponse *)theResponse {
id<MGMWebDavHandler> handler = [self handlerForConnection:theConnection];
NSMutableURLRequest *request = nil;
if ([handler respondsToSelector:@selector(willSendRequest:redirectResponse:)]) {
request = [[handler willSendRequest:theRequest redirectResponse:theResponse] mutableCopy];
[request setValue:MGMWebDavUA forHTTPHeaderField:MGMWebDavUserAgent];
if ([handler respondsToSelector:@selector(setRequest:)]) [handler setRequest:request];
return [request autorelease];
}
request = [theRequest mutableCopy];
if ([handler respondsToSelector:@selector(request)]) {
NSMutableURLRequest *oldRequest = [handler request];
[request setHTTPMethod:[oldRequest HTTPMethod]];
[request setAllHTTPHeaderFields:[oldRequest allHTTPHeaderFields]];
[request setHTTPBody:[oldRequest HTTPBody]];
}
[request setValue:MGMWebDavUA forHTTPHeaderField:MGMWebDavUserAgent];
if ([handler respondsToSelector:@selector(setRequest:)]) [handler setRequest:request];
return [request autorelease];
}
- (void)connection:(NSURLConnection *)theConnection didReceiveResponse:(NSHTTPURLResponse *)theResponse {
id<MGMWebDavHandler> handler = [self handlerForConnection:theConnection];
if ([handler respondsToSelector:@selector(didReceiveResponse:)])
[handler didReceiveResponse:theResponse];
}
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)theData {
id<MGMWebDavHandler> handler = [self handlerForConnection:theConnection];
if ([handler respondsToSelector:@selector(didReceiveData:)])
[handler didReceiveData:theData];
}
- (void)connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)theError {
id<MGMWebDavHandler> handler = [self handlerForConnection:theConnection];
if ([handler respondsToSelector:@selector(didFailWithError:)])
[handler didFailWithError:theError];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection {
id<MGMWebDavHandler> handler = [self handlerForConnection:theConnection];
if ([handler respondsToSelector:@selector(didFinishLoading)])
[handler didFinishLoading];
[handlers removeObject:handler];
}
@end

View File

@ -0,0 +1,13 @@
//
// MGMWebDavAddons.h
// CocoaShare
//
// Created by James on 1/28/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
@interface NSURL (MGMWebDavAddons)
- (NSURL *)appendPathComponent:(NSString *)theComponent;
@end

View File

@ -0,0 +1,37 @@
//
// MGMWebDavAddons.m
// CocoaShare
//
// Created by James on 1/28/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMWebDavAddons.h"
@implementation NSURL (MGMWebDavAddons)
- (NSURL *)appendPathComponent:(NSString *)theComponent {
NSMutableString *string = [NSMutableString string];
if ([self scheme]!=nil)
[string appendFormat:@"%@://", [self scheme]];
if ([self host]!=nil)
[string appendString:[self host]];
if ([self port]!=0)
[string appendFormat:@":%d", [self port]];
if ([self path]!=nil) {
if (theComponent!=nil) {
[string appendString:[[self path] stringByAppendingPathComponent:theComponent]];
if ([theComponent isEqual:@""] || [theComponent hasSuffix:@"/"])
[string appendString:@"/"];
} else {
[string appendString:[self path]];
if ([[self absoluteString] hasSuffix:@"/"])
[string appendString:@"/"];
}
} else {
[string appendString:[@"/" stringByAppendingPathComponent:theComponent]];
}
if ([self query]!=nil)
[string appendFormat:@"?%@", [self query]];
return [NSURL URLWithString:string];
}
@end

View File

@ -0,0 +1,40 @@
//
// MGMWebDavDelete.h
// CocoaShare
//
// Created by James on 1/29/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
extern NSString * const MGMWebDavMDELETE;
@class MGMWebDavDelete, MGMWebDav;
@protocol MGMWebDavDelegate;
@protocol MGMWebDavDeleteDelegate <MGMWebDavDelegate>
- (void)webDav:(MGMWebDav *)theSender error:(NSError *)theError deleting:(MGMWebDavDelete *)theDelete;
- (void)webDav:(MGMWebDav *)theSender deleted:(MGMWebDavDelete *)theDelete;
@end
@interface MGMWebDavDelete : NSObject {
id<MGMWebDavDeleteDelegate> delegate;
NSString *uri;
MGMWebDav *webDav;
NSMutableURLRequest *request;
NSURLConnection *connection;
NSHTTPURLResponse *response;
}
+ (id)deleteAtURI:(NSString *)theURI;
- (id)initWithURI:(NSString *)theURI;
- (void)setDelegate:(id)theDelegate;
- (id<MGMWebDavDeleteDelegate>)delegate;
- (void)setURI:(NSString *)theURI;
- (NSString *)URI;
- (NSMutableURLRequest *)request;
- (NSURLResponse *)response;
@end

View File

@ -0,0 +1,89 @@
//
// MGMWebDavDelete.m
// CocoaShare
//
// Created by James on 1/29/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMWebDavDelete.h"
#import "MGMWebDav.h"
NSString * const MGMWebDavMDELETE = @"DELETE";
@implementation MGMWebDavDelete
+ (id)deleteAtURI:(NSString *)theURI {
return [[[self alloc] initWithURI:theURI] autorelease];
}
- (id)initWithURI:(NSString *)theURI {
if ((self = [super init])) {
uri = [theURI retain];
}
return self;
}
- (void)dealloc {
[uri release];
[request release];
[connection release];
[response release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MGMWebDavDeleteDelegate>)delegate {
if (delegate==nil)
return (id<MGMWebDavDeleteDelegate>)[webDav delegate];
return delegate;
}
- (void)setURI:(NSString *)theURI {
[uri release];
uri = [theURI retain];
}
- (NSString *)URI {
return uri;
}
- (void)setWebDav:(MGMWebDav *)theWebDav {
webDav = theWebDav;
}
- (void)setConnection:(NSURLConnection *)theConnection {
[connection release];
connection = [theConnection retain];
}
- (NSURLConnection *)connection {
return connection;
}
- (void)setRequest:(NSMutableURLRequest *)theRequest {
[request release];
request = [theRequest retain];
}
- (NSMutableURLRequest *)request {
if (request==nil) {
request = [[NSMutableURLRequest requestWithURL:[[webDav rootURL] appendPathComponent:uri]] retain];
[request setHTTPMethod:MGMWebDavMDELETE];
}
return request;
}
- (void)didReceiveResponse:(NSHTTPURLResponse *)theResponse {
response = [theResponse retain];
if ([response statusCode]==204) {
if ([[self delegate] respondsToSelector:@selector(webDav:deleted:)]) [[self delegate] webDav:webDav deleted:self];
} else {
NSString *description = [NSString stringWithFormat:@"The response was returned as %@ and not %@.", [NSHTTPURLResponse localizedStringForStatusCode:[response statusCode]], [NSHTTPURLResponse localizedStringForStatusCode:204]];
NSError *error = [NSError errorWithDomain:MGMWebDavErrorDomain code:[response statusCode] userInfo:[NSDictionary dictionaryWithObject:description forKey:NSLocalizedDescriptionKey]];
if ([[self delegate] respondsToSelector:@selector(webDav:error:deleting:)]) [[self delegate] webDav:webDav error:error deleting:self];
}
}
- (void)didFailWithError:(NSError *)theError {
if ([[self delegate] respondsToSelector:@selector(webDav:error:deleting:)]) [[self delegate] webDav:webDav error:theError deleting:self];
}
- (NSURLResponse *)response {
return response;
}
@end

View File

@ -0,0 +1,53 @@
//
// MGMWebDavGet.h
// CocoaShare
//
// Created by James on 1/29/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
extern NSString * const MGMWebDavMGET;
@class MGMWebDavGet, MGMWebDav;
@protocol MGMWebDavDelegate;
@protocol MGMWebDavGetDelegate <MGMWebDavDelegate>
- (void)webDav:(MGMWebDav *)theSender get:(MGMWebDavGet *)theGet downloaded:(unsigned long)theBytes totalBytes:(unsigned long)theTotalBytes totalBytesExpected:(unsigned long)theExpectedBytes;
- (void)webDav:(MGMWebDav *)theSender error:(NSError *)theError getting:(MGMWebDavGet *)theGet;
- (void)webDav:(MGMWebDav *)theSender gotSuccessfully:(MGMWebDavGet *)theGet;
@end
@interface MGMWebDavGet : NSObject {
id<MGMWebDavGetDelegate> delegate;
NSString *uri;
MGMWebDav *webDav;
NSMutableURLRequest *request;
NSURLConnection *connection;
NSHTTPURLResponse *response;
NSString *file;
NSFileHandle *fileHandle;
NSMutableData *dataBuffer;
unsigned long totalExpected;
unsigned long totalDownloaded;
}
+ (id)getAtURI:(NSString *)theURI;
- (id)initWithURI:(NSString *)theURI;
- (void)setDelegate:(id)theDelegate;
- (id<MGMWebDavGetDelegate>)delegate;
- (void)setURI:(NSString *)theURI;
- (NSString *)URI;
- (void)setFile:(NSString *)theFile;
- (NSString *)file;
- (NSMutableURLRequest *)request;
- (NSURLResponse *)response;
- (NSData *)data;
@end

View File

@ -0,0 +1,135 @@
//
// MGMWebDavGet.m
// CocoaShare
//
// Created by James on 1/29/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMWebDavGet.h"
#import "MGMWebDav.h"
NSString * const MGMWebDavMGET = @"GET";
@implementation MGMWebDavGet
+ (id)getAtURI:(NSString *)theURI {
return [[[self alloc] initWithURI:theURI] autorelease];
}
- (id)initWithURI:(NSString *)theURI {
if ((self = [super init])) {
uri = [theURI retain];
}
return self;
}
- (void)dealloc {
[uri release];
[file release];
[fileHandle release];
[dataBuffer release];
[request release];
[connection release];
[response release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MGMWebDavGetDelegate>)delegate {
if (delegate==nil)
return (id<MGMWebDavGetDelegate>)[webDav delegate];
return delegate;
}
- (void)setURI:(NSString *)theURI {
[uri release];
uri = [theURI retain];
}
- (NSString *)URI {
return uri;
}
- (void)setFile:(NSString *)theFile {
[file release];
file = [theFile retain];
}
- (NSString *)file {
return file;
}
- (void)setWebDav:(MGMWebDav *)theWebDav {
webDav = theWebDav;
}
- (void)setConnection:(NSURLConnection *)theConnection {
[connection release];
connection = [theConnection retain];
}
- (NSURLConnection *)connection {
return connection;
}
- (void)setRequest:(NSMutableURLRequest *)theRequest {
[request release];
request = [theRequest retain];
}
- (NSMutableURLRequest *)request {
if (request==nil) {
request = [[NSMutableURLRequest requestWithURL:[[webDav rootURL] appendPathComponent:uri]] retain];
[request setHTTPMethod:MGMWebDavMGET];
NSFileManager *manager = [NSFileManager defaultManager];
if ([manager fileExistsAtPath:[file stringByDeletingLastPathComponent]]) {
[manager createFileAtPath:file contents:nil attributes:nil];
fileHandle = [[NSFileHandle fileHandleForWritingAtPath:file] retain];
} else {
dataBuffer = [NSMutableData new];
}
}
return request;
}
- (void)didReceiveResponse:(NSHTTPURLResponse *)theResponse {
response = [theResponse retain];
if ([response statusCode]!=200) {
[fileHandle closeFile];
[fileHandle release];
fileHandle = nil;
NSString *description = [NSString stringWithFormat:@"The response was returned as %@ and not %@.", [NSHTTPURLResponse localizedStringForStatusCode:[response statusCode]], [NSHTTPURLResponse localizedStringForStatusCode:200]];
NSError *error = [NSError errorWithDomain:MGMWebDavErrorDomain code:[response statusCode] userInfo:[NSDictionary dictionaryWithObject:description forKey:NSLocalizedDescriptionKey]];
if ([[self delegate] respondsToSelector:@selector(webDav:error:getting:)]) [[self delegate] webDav:webDav error:error getting:self];
[webDav cancelHandler:self];
}
totalExpected = [response expectedContentLength];
}
- (void)didReceiveData:(NSData *)theData {
totalDownloaded += [theData length];
if ([[self delegate] respondsToSelector:@selector(webDav:get:downloaded:totalBytes:totalBytesExpected:)]) [[self delegate] webDav:webDav get:self downloaded:[theData length] totalBytes:totalDownloaded totalBytesExpected:totalExpected];
if (fileHandle!=nil) {
[fileHandle writeData:theData];
[fileHandle synchronizeFile];
} else {
[dataBuffer appendData:theData];
}
}
- (void)didFailWithError:(NSError *)theError {
[fileHandle closeFile];
[fileHandle release];
fileHandle = nil;
if ([[self delegate] respondsToSelector:@selector(webDav:error:getting:)]) [[self delegate] webDav:webDav error:theError getting:self];
}
- (void)didFinishLoading {
[fileHandle closeFile];
[fileHandle release];
fileHandle = nil;
if ([[self delegate] respondsToSelector:@selector(webDav:gotSuccessfully:)]) [[self delegate] webDav:webDav gotSuccessfully:self];
}
- (NSURLResponse *)response {
return response;
}
- (NSData *)data {
return dataBuffer;
}
@end

View File

@ -0,0 +1,40 @@
//
// MGMWebDavMkCol.h
// CocoaShare
//
// Created by James on 1/29/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
extern NSString * const MGMWebDavMMKCOL;
@class MGMWebDavMkCol, MGMWebDav;
@protocol MGMWebDavDelegate;
@protocol MGMWebDavMkColDelegate <MGMWebDavDelegate>
- (void)webDav:(MGMWebDav *)theSender error:(NSError *)theError mkCol:(MGMWebDavMkCol *)theMkCol;
- (void)webDav:(MGMWebDav *)theSender mkCol:(MGMWebDavMkCol *)theMkCol;
@end
@interface MGMWebDavMkCol : NSObject {
id<MGMWebDavMkColDelegate> delegate;
NSString *uri;
MGMWebDav *webDav;
NSMutableURLRequest *request;
NSURLConnection *connection;
NSHTTPURLResponse *response;
}
+ (id)mkColAtURI:(NSString *)theURI;
- (id)initWithURI:(NSString *)theURI;
- (void)setDelegate:(id)theDelegate;
- (id<MGMWebDavMkColDelegate>)delegate;
- (void)setURI:(NSString *)theURI;
- (NSString *)URI;
- (NSMutableURLRequest *)request;
- (NSURLResponse *)response;
@end

View File

@ -0,0 +1,89 @@
//
// MGMWebDavMkCol.m
// CocoaShare
//
// Created by James on 1/29/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMWebDavMkCol.h"
#import "MGMWebDav.h"
NSString * const MGMWebDavMMKCOL = @"MKCOL";
@implementation MGMWebDavMkCol
+ (id)mkColAtURI:(NSString *)theURI {
return [[[self alloc] initWithURI:theURI] autorelease];
}
- (id)initWithURI:(NSString *)theURI {
if ((self = [super init])) {
uri = [theURI retain];
}
return self;
}
- (void)dealloc {
[uri release];
[request release];
[connection release];
[response release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MGMWebDavMkColDelegate>)delegate {
if (delegate==nil)
return (id<MGMWebDavMkColDelegate>)[webDav delegate];
return delegate;
}
- (void)setURI:(NSString *)theURI {
[uri release];
uri = [theURI retain];
}
- (NSString *)URI {
return uri;
}
- (void)setWebDav:(MGMWebDav *)theWebDav {
webDav = theWebDav;
}
- (void)setConnection:(NSURLConnection *)theConnection {
[connection release];
connection = [theConnection retain];
}
- (NSURLConnection *)connection {
return connection;
}
- (void)setRequest:(NSMutableURLRequest *)theRequest {
[request release];
request = [theRequest retain];
}
- (NSMutableURLRequest *)request {
if (request==nil) {
request = [[NSMutableURLRequest requestWithURL:[[webDav rootURL] appendPathComponent:uri]] retain];
[request setHTTPMethod:MGMWebDavMMKCOL];
}
return request;
}
- (void)didReceiveResponse:(NSHTTPURLResponse *)theResponse {
response = [theResponse retain];
if ([response statusCode]==201) {
if ([[self delegate] respondsToSelector:@selector(webDav:mkCol:)]) [[self delegate] webDav:webDav mkCol:self];
} else {
NSString *description = [NSString stringWithFormat:@"The response was returned as %@ and not %@.", [NSHTTPURLResponse localizedStringForStatusCode:[response statusCode]], [NSHTTPURLResponse localizedStringForStatusCode:201]];
NSError *error = [NSError errorWithDomain:MGMWebDavErrorDomain code:[response statusCode] userInfo:[NSDictionary dictionaryWithObject:description forKey:NSLocalizedDescriptionKey]];
if ([[self delegate] respondsToSelector:@selector(webDav:error:mkCol:)]) [[self delegate] webDav:webDav error:error mkCol:self];
}
}
- (void)didFailWithError:(NSError *)theError {
if ([[self delegate] respondsToSelector:@selector(webDav:error:mkCol:)]) [[self delegate] webDav:webDav error:theError mkCol:self];
}
- (NSURLResponse *)response {
return response;
}
@end

View File

@ -0,0 +1,41 @@
//
// MGMWebDavOptions.h
// CocoaShare
//
// Created by James on 1/28/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
extern NSString * const MGMWebDavMOPTIONS;
@class MGMWebDavOptions, MGMWebDav;
@protocol MGMWebDavDelegate;
@protocol MGMWebDavOptionsDelegate <MGMWebDavDelegate>
- (void)webDav:(MGMWebDav *)theSender error:(NSError *)theError recevingOptions:(MGMWebDavOptions *)theOptions;
- (void)webDav:(MGMWebDav *)theSender receivedOptions:(MGMWebDavOptions *)theOptions;
@end
@interface MGMWebDavOptions : NSObject {
id<MGMWebDavOptionsDelegate> delegate;
NSString *uri;
MGMWebDav *webDav;
NSMutableURLRequest *request;
NSURLConnection *connection;
NSHTTPURLResponse *response;
}
+ (id)optionsAtURI:(NSString *)theURI;
- (id)initWithURI:(NSString *)theURI;
- (void)setDelegate:(id)theDelegate;
- (id<MGMWebDavOptionsDelegate>)delegate;
- (void)setURI:(NSString *)theURI;
- (NSString *)URI;
- (NSMutableURLRequest *)request;
- (NSArray *)allowedMethods;
- (NSURLResponse *)response;
@end

View File

@ -0,0 +1,92 @@
//
// MGMWebDavOptions.m
// CocoaShare
//
// Created by James on 1/28/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMWebDavOptions.h"
#import "MGMWebDav.h"
NSString * const MGMWebDavMOPTIONS = @"OPTIONS";
@implementation MGMWebDavOptions
+ (id)optionsAtURI:(NSString *)theURI {
return [[[self alloc] initWithURI:theURI] autorelease];
}
- (id)initWithURI:(NSString *)theURI {
if ((self = [super init])) {
uri = [theURI retain];
}
return self;
}
- (void)dealloc {
[uri release];
[request release];
[connection release];
[response release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MGMWebDavOptionsDelegate>)delegate {
if (delegate==nil)
return (id<MGMWebDavOptionsDelegate>)[webDav delegate];
return delegate;
}
- (void)setURI:(NSString *)theURI {
[uri release];
uri = [theURI retain];
}
- (NSString *)URI {
return uri;
}
- (void)setWebDav:(MGMWebDav *)theWebDav {
webDav = theWebDav;
}
- (void)setConnection:(NSURLConnection *)theConnection {
[connection release];
connection = [theConnection retain];
}
- (NSURLConnection *)connection {
return connection;
}
- (void)setRequest:(NSMutableURLRequest *)theRequest {
[request release];
request = [theRequest retain];
}
- (NSMutableURLRequest *)request {
if (request==nil) {
request = [[NSMutableURLRequest requestWithURL:[[webDav rootURL] appendPathComponent:uri]] retain];
[request setHTTPMethod:MGMWebDavMOPTIONS];
}
return request;
}
- (void)didReceiveResponse:(NSHTTPURLResponse *)theResponse {
response = [theResponse retain];
if ([[theResponse allHeaderFields] objectForKey:@"Dav"]!=nil) {
if ([[self delegate] respondsToSelector:@selector(webDav:receivedOptions:)]) [[self delegate] webDav:webDav receivedOptions:self];
} else {
NSError *error = [NSError errorWithDomain:MGMWebDavErrorDomain code:1 userInfo:[NSDictionary dictionaryWithObject:@"The HTTP server does not have WebDav enabled in this directory." forKey:NSLocalizedDescriptionKey]];
if ([[self delegate] respondsToSelector:@selector(webDav:error:recevingOptions:)]) [[self delegate] webDav:webDav error:error recevingOptions:self];
}
}
- (void)didFailWithError:(NSError *)theError {
if ([[self delegate] respondsToSelector:@selector(webDav:error:recevingOptions:)]) [[self delegate] webDav:webDav error:theError recevingOptions:self];
}
- (NSArray *)allowedMethods {
NSString *allowed = [[response allHeaderFields] objectForKey:@"Allow"];
return [allowed componentsSeparatedByString:@","];
}
- (NSURLResponse *)response {
return response;
}
@end

View File

@ -0,0 +1,78 @@
//
// MGMWebDavPropFind.h
// CocoaShare
//
// Created by James on 1/28/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
extern NSString * const MGMWebDavMPROPFIND;
extern NSString * const MGMWebDavDepth;
extern NSString * const MGMWebDavPCreationDate;
extern NSString * const MGMWebDavPDisplayName;
extern NSString * const MGMWebDavPContentLength;
extern NSString * const MGMWebDavPContentType;
extern NSString * const MGMWebDavPETag;
extern NSString * const MGMWebDavPLastModified;
extern NSString * const MGMWebDavPResourceType;
extern NSString * const MGMWebDavPSupportedLock;
extern NSString * const MGMWebDavPQuotaAvailableBytes;
extern NSString * const MGMWebDavPQuotaUsedBytes;
extern NSString * const MGMWebDavPQuota;
extern NSString * const MGMWebDavPQuotaUsed;
extern NSString * const MGMWebDavPURL;
extern NSString * const MGMWebDavPURI;
extern NSString * const MGMWebDavPStatus;
extern NSString * const MGMWebDavPRCollection;
extern NSString * const MGMWebDavPRFile;
@class MGMWebDavPropFind, MGMWebDav;
@protocol MGMWebDavDelegate;
@protocol MGMWebDavPropFindDelegate <MGMWebDavDelegate>
- (void)webDav:(MGMWebDav *)theSender error:(NSError *)theError recevingProperties:(MGMWebDavPropFind *)thePropFind;
- (void)webDav:(MGMWebDav *)theSender receivedProperties:(MGMWebDavPropFind *)thePropFind;
@end
@interface MGMWebDavPropFind : NSObject {
id<MGMWebDavPropFindDelegate> delegate;
NSString *uri;
NSMutableArray *properties;
int depth;
MGMWebDav *webDav;
NSMutableURLRequest *request;
NSURLConnection *connection;
NSHTTPURLResponse *response;
NSMutableData *dataBuffer;
NSXMLDocument *xmlDocument;
NSMutableArray *contents;
}
+ (id)propfindAtURI:(NSString *)theURI;
- (id)initWithURI:(NSString *)theURI;
- (void)setDelegate:(id)theDelegate;
- (id<MGMWebDavPropFindDelegate>)delegate;
- (void)setURI:(NSString *)theURI;
- (NSString *)URI;
- (NSArray *)properties;
- (void)addProperty:(NSString *)theProperty;
- (void)removeProperty:(NSString *)theProperty;
- (void)setDepth:(int)theDepth;
- (int)depth;
- (NSMutableURLRequest *)request;
- (NSURLResponse *)response;
- (NSData *)data;
- (NSXMLDocument *)xmlDocument;
- (NSArray *)contents;
@end

View File

@ -0,0 +1,244 @@
//
// MGMWebDavPropFind.m
// CocoaShare
//
// Created by James on 1/28/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMWebDavPropFind.h"
#import "MGMWebDav.h"
NSString * const MGMWebDavMPROPFIND = @"PROPFIND";
NSString * const MGMWebDavDepth = @"Depth";
NSString * const MGMWebDavPCreationDate = @"creationdate";
NSString * const MGMWebDavPDisplayName = @"displayname";
NSString * const MGMWebDavPContentLength = @"getcontentlength";
NSString * const MGMWebDavPContentType = @"getcontenttype";
NSString * const MGMWebDavPETag = @"getetag";
NSString * const MGMWebDavPLastModified = @"getlastmodified";
NSString * const MGMWebDavPResourceType = @"resourcetype";
NSString * const MGMWebDavPSupportedLock = @"supportedlock";
NSString * const MGMWebDavPQuotaAvailableBytes = @"quota-available-bytes";
NSString * const MGMWebDavPQuotaUsedBytes = @"quota-used-bytes";
NSString * const MGMWebDavPQuota = @"quota";
NSString * const MGMWebDavPQuotaUsed = @"quotaused";
NSString * const MGMWebDavPURL = @"url";
NSString * const MGMWebDavPURI = @"uri";
NSString * const MGMWebDavPStatus = @"status";
NSString * const MGMWebDavPRCollection = @"collection";
NSString * const MGMWebDavPRFile = @"file";
@implementation MGMWebDavPropFind
+ (id)propfindAtURI:(NSString *)theURI {
return [[[self alloc] initWithURI:theURI] autorelease];
}
- (id)initWithURI:(NSString *)theURI {
if ((self = [self init])) {
uri = [theURI retain];
depth = 0;
}
return self;
}
- (id)init {
if ((self = [super init])) {
properties = [NSMutableArray new];
dataBuffer = [NSMutableData new];
contents = [NSMutableArray new];
}
return self;
}
- (void)dealloc {
[uri release];
[properties release];
[request release];
[connection release];
[response release];
[dataBuffer release];
[xmlDocument release];
[contents release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MGMWebDavPropFindDelegate>)delegate {
if (delegate==nil)
return (id<MGMWebDavPropFindDelegate>)[webDav delegate];
return delegate;
}
- (void)setURI:(NSString *)theURI {
[uri release];
uri = [theURI retain];
}
- (NSString *)URI {
return uri;
}
- (NSArray *)properties {
return properties;
}
- (void)addProperty:(NSString *)theProperty {
if (![properties containsObject:theProperty])
[properties addObject:theProperty];
}
- (void)removeProperty:(NSString *)theProperty {
[properties removeObject:theProperty];
}
- (void)setDepth:(int)theDepth {
depth = theDepth;
}
- (int)depth {
return depth;
}
- (void)setWebDav:(MGMWebDav *)theWebDav {
webDav = theWebDav;
}
- (void)setConnection:(NSURLConnection *)theConnection {
[connection release];
connection = [theConnection retain];
}
- (NSURLConnection *)connection {
return connection;
}
- (void)setRequest:(NSMutableURLRequest *)theRequest {
[request release];
request = [theRequest retain];
}
- (NSMutableURLRequest *)request {
if (request==nil) {
request = [[NSMutableURLRequest requestWithURL:[[webDav rootURL] appendPathComponent:uri]] retain];
[request setHTTPMethod:MGMWebDavMPROPFIND];
[request setValue:[[NSNumber numberWithInt:depth] stringValue] forHTTPHeaderField:MGMWebDavDepth];
[request setValue:MGMWebDavXMLType forHTTPHeaderField:MGMWebDavContentType];
NSMutableString *xml = [NSMutableString string];
[xml appendString:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
[xml appendString:@"<D:propfind xmlns:D=\"DAV:\">"];
if ([properties count]>0) {
[xml appendString:@"<D:prop>"];
for (int i=0; i<[properties count]; i++) {
[xml appendFormat:@"<D:%@/>", [properties objectAtIndex:i]];
}
[xml appendString:@"</D:prop>"];
} else {
[xml appendString:@"<D:allprop/>"];
}
[xml appendString:@"</D:propfind>"];
[request setHTTPBody:[xml dataUsingEncoding:NSUTF8StringEncoding]];
}
return request;
}
- (void)didReceiveResponse:(NSHTTPURLResponse *)theResponse {
response = [theResponse retain];
if ([response statusCode]!=207) {
NSString *description = [NSString stringWithFormat:@"The response was returned as %@ and not %@.", [NSHTTPURLResponse localizedStringForStatusCode:[response statusCode]], [NSHTTPURLResponse localizedStringForStatusCode:207]];
NSError *error = [NSError errorWithDomain:MGMWebDavErrorDomain code:[response statusCode] userInfo:[NSDictionary dictionaryWithObject:description forKey:NSLocalizedDescriptionKey]];
if ([[self delegate] respondsToSelector:@selector(webDav:error:recevingProperties:)]) [[self delegate] webDav:webDav error:error recevingProperties:self];
[webDav cancelHandler:self];
}
}
- (void)didReceiveData:(NSData *)theData {
[dataBuffer appendData:theData];
}
- (void)didFailWithError:(NSError *)theError {
if ([[self delegate] respondsToSelector:@selector(webDav:error:recevingProperties:)]) [[self delegate] webDav:webDav error:theError recevingProperties:self];
}
- (void)didFinishLoading {
NSError *error = nil;
xmlDocument = [[NSXMLDocument alloc] initWithData:dataBuffer options:0 error:&error];
if (error!=nil)
NSLog(@"%@", error);
NSArray *responses = [[xmlDocument rootElement] elementsForLocalName:@"response" URI:@"DAV:"];
for (unsigned long i=0; i<[responses count]; i++) {
NSXMLElement *thisResponse = [responses objectAtIndex:i];
NSMutableDictionary *content = [NSMutableDictionary dictionary];
NSArray *hrefElements = [thisResponse elementsForLocalName:@"href" URI:@"DAV:"];
if ([hrefElements count]<=0)
continue;
NSString *href = [[hrefElements objectAtIndex:0] stringValue];
NSURL *url = nil;
if ([href hasPrefix:@"http"])
url = [NSURL URLWithString:href];
else
url = [NSURL URLWithString:href relativeToURL:[request URL]];
[content setObject:url forKey:MGMWebDavPURL];
NSString *path = [url path];
NSRange range = [path rangeOfString:[[webDav rootURL] path] options:NSCaseInsensitiveSearch];
if (range.length!=0 && range.location==0) {
path = [path substringFromIndex:range.length];
if ([[url absoluteString] hasSuffix:@"/"])
path = [path stringByAppendingString:@"/"];
[content setObject:path forKey:MGMWebDavPURI];
}
NSArray *propStats = [thisResponse elementsForLocalName:@"propstat" URI:@"DAV:"];
if ([propStats count]>0) {
NSXMLElement *propStat = [propStats objectAtIndex:0];
NSArray *props = [propStat elementsForLocalName:@"prop" URI:@"DAV:"];
if ([props count]>0) {
props = [[props objectAtIndex:0] children];
for (int i=0; i<[props count]; i++) {
NSXMLElement *prop = [props objectAtIndex:i];
NSString *name = [prop localName];
if ([name isEqual:MGMWebDavPResourceType]) {
if ([prop childCount]>0)
[content setObject:[[prop childAtIndex:0] localName] forKey:name];
else
[content setObject:MGMWebDavPRFile forKey:name];
} else if ([name isEqual:MGMWebDavPCreationDate]) {
NSString *dateString = [prop stringValue];
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"GMT"]];
NSDate *date = [dateFormatter dateFromString:dateString];
[dateFormatter release];
[content setObject:date forKey:name];
} else if ([name isEqual:MGMWebDavPLastModified]) {
NSString *dateString = [prop stringValue];
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss zzz"];
NSDate *date = [dateFormatter dateFromString:dateString];
[dateFormatter release];
[content setObject:date forKey:name];
} else if ([name isEqual:MGMWebDavPSupportedLock]) {
// Don't exactly understand what this is.
} else {
if ([prop stringValue]!=nil)
[content setObject:[prop stringValue] forKey:name];
}
}
}
NSArray *statuses = [propStat elementsForLocalName:@"status" URI:@"DAV:"];
if ([statuses count]>0)
[content setObject:[[statuses objectAtIndex:0] stringValue] forKey:MGMWebDavPStatus];
}
[contents addObject:content];
}
if ([[self delegate] respondsToSelector:@selector(webDav:receivedProperties:)]) [[self delegate] webDav:webDav receivedProperties:self];
}
- (NSURLResponse *)response {
return response;
}
- (NSData *)data {
return dataBuffer;
}
- (NSXMLDocument *)xmlDocument {
return xmlDocument;
}
- (NSArray *)contents {
return contents;
}
@end

View File

@ -0,0 +1,45 @@
//
// MGMWebDavPut.h
// CocoaShare
//
// Created by James on 1/29/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
extern NSString * const MGMWebDavMPUT;
@class MGMWebDavPut, MGMWebDav;
@protocol MGMWebDavDelegate;
@protocol MGMWebDavPutDelegate <MGMWebDavDelegate>
- (void)webDav:(MGMWebDav *)theSender put:(MGMWebDavPut *)thePut uploaded:(unsigned long)theBytes totalBytes:(unsigned long)theTotalBytes totalBytesExpected:(unsigned long)theExpectedBytes;
- (void)webDav:(MGMWebDav *)theSender error:(NSError *)theError putting:(MGMWebDavPut *)thePut;
- (void)webDav:(MGMWebDav *)theSender successfullyPut:(MGMWebDavPut *)thePut;
@end
@interface MGMWebDavPut : NSObject {
id<MGMWebDavPutDelegate> delegate;
NSString *uri;
MGMWebDav *webDav;
NSData *data;
NSMutableURLRequest *request;
NSURLConnection *connection;
NSHTTPURLResponse *response;
}
+ (id)putAtURI:(NSString *)theURI;
- (id)initWithURI:(NSString *)theURI;
- (void)setDelegate:(id)theDelegate;
- (id<MGMWebDavPutDelegate>)delegate;
- (void)setURI:(NSString *)theURI;
- (NSString *)URI;
- (void)setData:(NSData *)theData;
- (NSData *)data;
- (NSMutableURLRequest *)request;
- (NSURLResponse *)response;
@end

View File

@ -0,0 +1,102 @@
//
// MGMWebDavPut.m
// CocoaShare
//
// Created by James on 1/29/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMWebDavPut.h"
#import "MGMWebDav.h"
NSString * const MGMWebDavMPUT = @"PUT";
@implementation MGMWebDavPut
+ (id)putAtURI:(NSString *)theURI {
return [[[self alloc] initWithURI:theURI] autorelease];
}
- (id)initWithURI:(NSString *)theURI {
if ((self = [super init])) {
uri = [theURI retain];
}
return self;
}
- (void)dealloc {
[uri release];
[data release];
[request release];
[connection release];
[response release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MGMWebDavPutDelegate>)delegate {
if (delegate==nil)
return (id<MGMWebDavPutDelegate>)[webDav delegate];
return delegate;
}
- (void)setURI:(NSString *)theURI {
[uri release];
uri = [theURI retain];
}
- (NSString *)URI {
return uri;
}
- (void)setData:(NSData *)theData {
[data release];
data = [theData retain];
}
- (NSData *)data {
return data;
}
- (void)setWebDav:(MGMWebDav *)theWebDav {
webDav = theWebDav;
}
- (void)setConnection:(NSURLConnection *)theConnection {
[connection release];
connection = [theConnection retain];
}
- (NSURLConnection *)connection {
return connection;
}
- (void)setRequest:(NSMutableURLRequest *)theRequest {
[request release];
request = [theRequest retain];
}
- (NSMutableURLRequest *)request {
if (request==nil) {
request = [[NSMutableURLRequest requestWithURL:[[webDav rootURL] appendPathComponent:uri]] retain];
[request setHTTPMethod:MGMWebDavMPUT];
[request setHTTPBody:data];
}
return request;
}
- (void)uploaded:(unsigned long)theBytes totalBytes:(unsigned long)theTotalBytes totalBytesExpected:(unsigned long)theExpectedBytes {
if ([[self delegate] respondsToSelector:@selector(webDav:put:uploaded:totalBytes:totalBytesExpected:)]) [[self delegate] webDav:webDav put:self uploaded:theBytes totalBytes:theTotalBytes totalBytesExpected:theExpectedBytes];
}
- (void)didReceiveResponse:(NSHTTPURLResponse *)theResponse {
response = [theResponse retain];
if ([response statusCode]==201 || [response statusCode]==204) {
if ([[self delegate] respondsToSelector:@selector(webDav:successfullyPut:)]) [[self delegate] webDav:webDav successfullyPut:self];
} else {
NSString *description = [NSString stringWithFormat:@"The response was returned as %@ and not %@.", [NSHTTPURLResponse localizedStringForStatusCode:[response statusCode]], [NSHTTPURLResponse localizedStringForStatusCode:201]];
NSError *error = [NSError errorWithDomain:MGMWebDavErrorDomain code:[response statusCode] userInfo:[NSDictionary dictionaryWithObject:description forKey:NSLocalizedDescriptionKey]];
if ([[self delegate] respondsToSelector:@selector(webDav:error:putting:)]) [[self delegate] webDav:webDav error:error putting:self];
}
}
- (void)didFailWithError:(NSError *)theError {
if ([[self delegate] respondsToSelector:@selector(webDav:error:putting:)]) [[self delegate] webDav:webDav error:theError putting:self];
}
- (NSURLResponse *)response {
return response;
}
@end

View File

@ -0,0 +1,26 @@
//
// MGMAccountPane.h
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
#import <MGMUsers/MGMUsers.h>
@class MGMController;
@interface MGMAccountPane : MGMPreferencesPane {
MGMController *controller;
IBOutlet NSView *view;
IBOutlet NSPopUpButton *typePopUp;
NSView *plugInView;
}
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
+ (NSString *)title;
- (NSView *)preferencesView;
- (IBAction)typeChanged:(id)sender;
@end

View File

@ -0,0 +1,68 @@
//
// MGMAccountPane.m
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMAccountPane.h"
#import "MGMController.h"
@implementation MGMAccountPane
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
if (self = [super initWithPreferences:thePreferences]) {
if (![NSBundle loadNibNamed:@"AccountPane" owner:self]) {
NSLog(@"Error loading Account pane");
} else {
controller = [MGMController sharedController];
NSArray *accountPlugIns = [controller accountPlugIns];
for (int i=0; i<[accountPlugIns count]; i++) {
id<MGMPlugInProtocol> plugIn = [accountPlugIns objectAtIndex:i];
NSString *name = ([plugIn respondsToSelector:@selector(plugInName)] ? [plugIn plugInName] : @"Unkown name");
[typePopUp addItemWithTitle:name];
}
[typePopUp selectItemAtIndex:[controller currentPlugInIndex]];
plugInView = nil;
if ([[controller currentPlugIn] respondsToSelector:@selector(plugInView)]) plugInView = [[controller currentPlugIn] plugInView];
NSRect plugInFrame = [plugInView frame];
[view setFrame:NSMakeRect(0, 0, (plugInFrame.size.width<130 ? 130 : plugInFrame.size.width), (plugInFrame.size.height<20 ? 20 : plugInFrame.size.height)+36)];
[view addSubview:plugInView];
}
}
return self;
}
- (void)dealloc {
[view release];
if ([[controller currentPlugIn] respondsToSelector:@selector(releaseView)]) [[controller currentPlugIn] releaseView];
[super dealloc];
}
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
[theItem setLabel:[self title]];
[theItem setPaletteLabel:[theItem label]];
[theItem setImage:[NSImage imageNamed:@"Account"]];
}
+ (NSString *)title {
return @"Account";
}
- (NSView *)preferencesView {
return view;
}
- (IBAction)typeChanged:(id)sender {
[plugInView removeFromSuperview];
plugInView = nil;
if ([[controller currentPlugIn] respondsToSelector:@selector(releaseView)]) [[controller currentPlugIn] releaseView];
[controller setCurrentPlugIn:[[controller accountPlugIns] objectAtIndex:[typePopUp indexOfSelectedItem]]];
[typePopUp selectItemAtIndex:[controller currentPlugInIndex]];
if ([[controller currentPlugIn] respondsToSelector:@selector(plugInView)]) plugInView = [[controller currentPlugIn] plugInView];
NSRect plugInFrame = [plugInView frame];
NSRect viewFrame = NSMakeRect(0, 0, (plugInFrame.size.width<130 ? 130 : plugInFrame.size.width), (plugInFrame.size.height<20 ? 20 : plugInFrame.size.height)+36);
NSWindow *preferencesWindow = [preferences preferencesWindow];
NSSize toolbarSize = [preferencesWindow toolbarSize];
NSRect currentRect = [preferencesWindow frame];
[preferencesWindow setFrame:NSMakeRect(currentRect.origin.x, currentRect.origin.y - ((viewFrame.size.height+toolbarSize.height) - currentRect.size.height), viewFrame.size.width, viewFrame.size.height+toolbarSize.height) display:YES animate:YES];
[view addSubview:plugInView];
}
@end

View File

@ -0,0 +1,46 @@
//
// MGMAutoUploadPane.h
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
#import <MGMUsers/MGMUsers.h>
@class MGMController;
@interface MGMAutoUploadPane : MGMPreferencesPane {
MGMController *controller;
IBOutlet NSView *view;
IBOutlet NSTableView *filtersTable;
IBOutlet NSButton *addButton;
IBOutlet NSButton *removeButton;
IBOutlet NSTextField *pathField;
IBOutlet NSButton *choosePathButton;
IBOutlet NSTextField *filterField;
IBOutlet NSTextField *testField;
IBOutlet NSTextField *testStatusField;
IBOutlet NSMenu *addMenu;
int currentFilter;
}
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
+ (NSString *)title;
- (NSView *)preferencesView;
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification;
- (IBAction)addFilter:(id)sender;
- (IBAction)addNewFilter:(id)sender;
- (IBAction)addScreenshotFilter:(id)sender;
- (IBAction)removeFilter:(id)sender;
- (IBAction)choosePath:(id)sender;
- (IBAction)pathChanged:(id)sender;
- (IBAction)filterChanged:(id)sender;
- (IBAction)test:(id)sender;
@end

View File

@ -0,0 +1,145 @@
//
// MGMAutoUploadPane.m
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMAutoUploadPane.h"
#import "MGMController.h"
#import "RegexKitLite.h"
@implementation MGMAutoUploadPane
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
if (self = [super initWithPreferences:thePreferences]) {
if (![NSBundle loadNibNamed:@"AutoUploadPane" owner:self]) {
NSLog(@"Error loading Auto Upload pane");
} else {
controller = [MGMController sharedController];
[filtersTable reloadData];
[self tableViewSelectionDidChange:nil];
}
}
return self;
}
- (void)dealloc {
[view release];
[addMenu release];
[super dealloc];
}
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
[theItem setLabel:[self title]];
[theItem setPaletteLabel:[theItem label]];
[theItem setImage:[NSImage imageNamed:@"AutoUpload"]];
}
+ (NSString *)title {
return @"Auto Upload";
}
- (NSView *)preferencesView {
return view;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
return [[controller filters] count];
}
- (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)theTableColumn row:(NSInteger)rowIndex {
if ([[theTableColumn identifier] isEqual:@"filter"]) {
return [[[controller filters] objectAtIndex:rowIndex] objectForKey:MGMFFilter];
} else if ([[theTableColumn identifier] isEqual:@"path"]) {
return [[[controller filters] objectAtIndex:rowIndex] objectForKey:MGMFPath];
}
return @"";
}
- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
if ([filtersTable selectedRow]>=0) {
currentFilter = [filtersTable selectedRow];
[removeButton setEnabled:YES];
[pathField setEnabled:YES];
[pathField setStringValue:[[[controller filters] objectAtIndex:currentFilter] objectForKey:MGMFPath]];
[choosePathButton setEnabled:YES];
[filterField setEnabled:YES];
[filterField setStringValue:[[[controller filters] objectAtIndex:currentFilter] objectForKey:MGMFFilter]];
[testField setEnabled:YES];
} else {
[removeButton setEnabled:NO];
[pathField setEnabled:NO];
[pathField setStringValue:@""];
[choosePathButton setEnabled:NO];
[filterField setEnabled:NO];
[filterField setStringValue:@""];
[testField setEnabled:NO];
}
}
- (IBAction)addFilter:(id)sender {
NSPoint location = [addButton frame].origin;
location.y += 20;
NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseUp location:location modifierFlags:0 timestamp:0 windowNumber:[[preferences preferencesWindow] windowNumber] context:nil eventNumber:0 clickCount:1 pressure:0];
[NSMenu popUpContextMenu:addMenu withEvent:event forView:addButton];
}
- (IBAction)addNewFilter:(id)sender {
[[controller filters] addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"", MGMFPath, @"", MGMFFilter, nil]];
[filtersTable reloadData];
int index = [[controller filters] count]-1;
[filtersTable selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
[NSThread detachNewThreadSelector:@selector(saveFilters) toTarget:controller withObject:nil];
}
- (IBAction)addScreenshotFilter:(id)sender {
[[controller filters] addObject:[NSDictionary dictionaryWithObjectsAndKeys:@"~/Desktop", MGMFPath, @"(?i)Screen shot .+ at .+\\.(?:bmp|gif|jpg|pdf|pict|png|sgi|tga|tif|tiff)\\z|Picture [0-9]+\\.(?:bmp|gif|jpg|pdf|pict|png|sgi|tga|tif|tiff)\\z", MGMFFilter, nil]];
[filtersTable reloadData];
int index = [[controller filters] count]-1;
[filtersTable selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
[NSThread detachNewThreadSelector:@selector(saveFilters) toTarget:controller withObject:nil];
}
- (IBAction)removeFilter:(id)sender {
if ([filtersTable selectedRow]>=0) {
[[controller filters] removeObjectAtIndex:[filtersTable selectedRow]];
[filtersTable deselectAll:self];
[filtersTable reloadData];
[NSThread detachNewThreadSelector:@selector(saveFilters) toTarget:controller withObject:nil];
}
}
- (IBAction)choosePath:(id)sender {
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setCanChooseFiles:NO];
[panel setCanChooseDirectories:YES];
[panel setResolvesAliases:YES];
[panel setAllowsMultipleSelection:NO];
[panel setTitle:@"Choose Folder"];
[panel setPrompt:@"Choose"];
int returnCode = [panel runModal];
if (returnCode==NSOKButton) {
NSString *path = [[[panel URLs] objectAtIndex:0] path];
[pathField setStringValue:path];
NSMutableDictionary *filter = [[[controller filters] objectAtIndex:currentFilter] mutableCopy];
[filter setObject:path forKey:MGMFPath];
[[controller filters] replaceObjectAtIndex:currentFilter withObject:filter];
[filter release];
[filtersTable reloadData];
[NSThread detachNewThreadSelector:@selector(saveFilters) toTarget:controller withObject:nil];
}
}
- (IBAction)pathChanged:(id)sender {
NSMutableDictionary *filter = [[[controller filters] objectAtIndex:currentFilter] mutableCopy];
[filter setObject:[pathField stringValue] forKey:MGMFPath];
[[controller filters] replaceObjectAtIndex:currentFilter withObject:filter];
[filter release];
[filtersTable reloadData];
[NSThread detachNewThreadSelector:@selector(saveFilters) toTarget:controller withObject:nil];
}
- (IBAction)filterChanged:(id)sender {
NSMutableDictionary *filter = [[[controller filters] objectAtIndex:currentFilter] mutableCopy];
[filter setObject:[filterField stringValue] forKey:MGMFFilter];
[[controller filters] replaceObjectAtIndex:currentFilter withObject:filter];
[filter release];
[filtersTable reloadData];
[NSThread detachNewThreadSelector:@selector(saveFilters) toTarget:controller withObject:nil];
[self test:self];
}
- (IBAction)test:(id)sender {
BOOL result = [[testField stringValue] isMatchedByRegex:[filterField stringValue]];
[testStatusField setStringValue:(result ? @"Match" : @"No Match")];
}
@end

View File

@ -0,0 +1,36 @@
//
// MGMEventsPane.h
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
#import <MGMUsers/MGMUsers.h>
@interface MGMEventsPane : MGMPreferencesPane {
IBOutlet NSView *view;
IBOutlet NSPopUpButton *eventPopUp;
IBOutlet NSPopUpButton *soundPopUp;
IBOutlet NSTextField *moveToField;
IBOutlet NSButton *moveToChooseButton;
IBOutlet NSMatrix *deleteMatrix;
IBOutlet NSButton *growlButton;
}
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
+ (NSString *)title;
- (NSView *)preferencesView;
- (NSArray *)sounds;
- (IBAction)eventChange:(id)sender;
- (IBAction)soundChange:(id)sender;
- (IBAction)moveChange:(id)sender;
- (IBAction)moveChoose:(id)sender;
- (IBAction)deleteChange:(id)sender;
- (IBAction)growlChange:(id)sender;
@end

View File

@ -0,0 +1,150 @@
//
// MGMEventsPane.m
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMEventsPane.h"
#import "MGMFileManager.h"
#import "MGMController.h"
@implementation MGMEventsPane
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
if (self = [super initWithPreferences:thePreferences]) {
if (![NSBundle loadNibNamed:@"EventsPane" owner:self]) {
NSLog(@"Error loading Events pane");
} else {
NSArray *sounds = [[self sounds] retain];
NSMenu *soundsMenu = [[NSMenu new] autorelease];
NSMenuItem *noneMenu = [[NSMenuItem new] autorelease];
[noneMenu setTitle:@"No Sound"];
[soundsMenu addItem:noneMenu];
[soundsMenu addItem:[NSMenuItem separatorItem]];
int selectedPath = -1;
NSString *currentPath = [preferences objectForKey:[NSString stringWithFormat:MGMESound, [eventPopUp indexOfSelectedItem]]];
for (int i=0; i<[sounds count]; i++) {
if ([[sounds objectAtIndex:i] isEqual:currentPath])
selectedPath = i;
NSMenuItem *menuItem = [[NSMenuItem new] autorelease];
[menuItem setTitle:[[[sounds objectAtIndex:i] lastPathComponent] stringByDeletingPathExtension]];
[menuItem setRepresentedObject:[sounds objectAtIndex:i]];
[soundsMenu addItem:menuItem];
}
[soundPopUp setMenu:soundsMenu];
if (selectedPath!=-1)
[soundPopUp selectItemAtIndex:selectedPath+2];
[moveToField setEnabled:NO];
[moveToChooseButton setEnabled:NO];
[deleteMatrix setEnabled:NO];
[growlButton setState:([preferences boolForKey:[NSString stringWithFormat:MGMEGrowl, [eventPopUp indexOfSelectedItem]]] ? NSOnState : NSOffState)];
}
}
return self;
}
- (void)dealloc {
[view release];
[super dealloc];
}
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
[theItem setLabel:[self title]];
[theItem setPaletteLabel:[theItem label]];
[theItem setImage:[NSImage imageNamed:@"Events"]];
}
+ (NSString *)title {
return @"Events";
}
- (NSView *)preferencesView {
return view;
}
- (NSArray *)sounds {
NSFileManager *manager = [NSFileManager defaultManager];
NSMutableArray *sounds = [NSMutableArray array];
NSString *systemSoundsPath = @"/System/Library/Sounds/";
NSString *userSoundsPath = [@"~/Library/Sounds/" stringByExpandingTildeInPath];
NSArray *allowedExtensions = [NSArray arrayWithObjects:@"aiff", @"aif", @"mp3", @"wav", @"au", @"m4a", @"caf", nil];
NSArray *checkPaths = [NSArray arrayWithObjects:systemSoundsPath, userSoundsPath, nil];
for (int i=0; i<[checkPaths count]; i++) {
NSDirectoryEnumerator *soundFolders = [manager enumeratorAtPath:[checkPaths objectAtIndex:i]];
NSString *soundName = nil;
while ((soundName = [soundFolders nextObject])) {
NSString *path = [[[checkPaths objectAtIndex:i] stringByAppendingPathComponent:soundName] stringByResolvingSymlinksInPath];
if ([allowedExtensions containsObject:[[soundName pathExtension] lowercaseString]])
[sounds addObject:path];
}
}
return sounds;
}
- (IBAction)eventChange:(id)sender {
NSArray *sounds = [soundPopUp itemArray];
int selectedPath = -1;
NSString *currentPath = [preferences objectForKey:[NSString stringWithFormat:MGMESound, [eventPopUp indexOfSelectedItem]]];
for (int i=0; i<[sounds count]; i++) {
if ([[[sounds objectAtIndex:i] representedObject] isEqual:currentPath]) {
selectedPath = i;
break;
}
}
if (selectedPath==-1)
[soundPopUp selectItemAtIndex:0];
else
[soundPopUp selectItemAtIndex:selectedPath+2];
if ([eventPopUp indexOfSelectedItem]==MGMEUploadingAutomatic || [eventPopUp indexOfSelectedItem]==MGMEUploading) {
[moveToField setEnabled:NO];
[moveToField setStringValue:@""];
[moveToChooseButton setEnabled:NO];
[deleteMatrix selectCellAtRow:0 column:0];
[deleteMatrix setEnabled:NO];
} else {
[moveToField setEnabled:YES];
NSString *path = [preferences objectForKey:[NSString stringWithFormat:MGMEPath, [eventPopUp indexOfSelectedItem]]];
if (path!=nil)
[moveToField setStringValue:path];
[moveToChooseButton setEnabled:YES];
[deleteMatrix selectCellAtRow:0 column:[preferences integerForKey:[NSString stringWithFormat:MGMEDelete, [eventPopUp indexOfSelectedItem]]]];
[deleteMatrix setEnabled:YES];
}
[growlButton setState:([preferences boolForKey:[NSString stringWithFormat:MGMEGrowl, [eventPopUp indexOfSelectedItem]]] ? NSOnState : NSOffState)];
}
- (IBAction)soundChange:(id)sender {
if ([[soundPopUp selectedItem] representedObject]!=nil) {
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:[[soundPopUp selectedItem] representedObject] byReference:YES];
[sound setDelegate:self];
[sound play];
[preferences setObject:[[soundPopUp selectedItem] representedObject] forKey:[NSString stringWithFormat:MGMESound, [eventPopUp indexOfSelectedItem]]];
}
}
- (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)finishedPlaying {
if (finishedPlaying)
[sound release];
}
- (IBAction)moveChange:(id)sender {
[preferences setObject:[moveToField stringValue] forKey:[preferences objectForKey:[NSString stringWithFormat:MGMEPath, [eventPopUp indexOfSelectedItem]]]];
}
- (IBAction)moveChoose:(id)sender {
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setCanChooseFiles:NO];
[panel setCanChooseDirectories:YES];
[panel setResolvesAliases:YES];
[panel setAllowsMultipleSelection:NO];
[panel setTitle:@"Choose Folder"];
[panel setPrompt:@"Choose"];
int returnCode = [panel runModal];
if (returnCode==NSOKButton) {
NSString *path = [[[panel URLs] objectAtIndex:0] path];
[moveToField setStringValue:path];
[preferences setObject:path forKey:[preferences objectForKey:[NSString stringWithFormat:MGMEPath, [eventPopUp indexOfSelectedItem]]]];
}
}
- (IBAction)deleteChange:(id)sender {
[preferences setInteger:[deleteMatrix selectedColumn] forKey:[NSString stringWithFormat:MGMEDelete, [eventPopUp indexOfSelectedItem]]];
}
- (IBAction)growlChange:(id)sender {
[preferences setBool:([growlButton state]==NSOnState) forKey:[NSString stringWithFormat:MGMEGrowl, [eventPopUp indexOfSelectedItem]]];
}
@end

View File

@ -0,0 +1,30 @@
//
// MGMGeneralPane.h
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
#import <MGMUsers/MGMUsers.h>
@interface MGMGeneralPane : MGMPreferencesPane {
IBOutlet NSView *view;
IBOutlet NSMatrix *display;
IBOutlet NSButton *startup;
IBOutlet NSMatrix *uploadName;
IBOutlet NSTextField *historyCountField;
IBOutlet NSButton *growlErrors;
}
- (id)initWithPreferences:(MGMPreferences *)thePreferences;
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem;
+ (NSString *)title;
- (NSView *)preferencesView;
- (IBAction)changeDisplay:(id)sender;
- (IBAction)changeStartup:(id)sender;
- (IBAction)changeUploadName:(id)sender;
- (IBAction)changeHistoryCount:(id)sender;
- (IBAction)changeGrowlErrors:(id)sender;
@end

View File

@ -0,0 +1,81 @@
//
// MGMGeneralPane.m
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import "MGMGeneralPane.h"
#import "MGMController.h"
#import "MGMLoginItems.h"
@implementation MGMGeneralPane
- (id)initWithPreferences:(MGMPreferences *)thePreferences {
if (self = [super initWithPreferences:thePreferences]) {
if (![NSBundle loadNibNamed:@"GeneralPane" owner:self]) {
NSLog(@"Error loading General pane");
} else {
[display selectCellAtRow:[preferences integerForKey:MGMDisplay] column:0];
[startup setState:([preferences boolForKey:MGMStartup] ? NSOnState : NSOffState)];
[uploadName selectCellAtRow:[preferences integerForKey:MGMUploadName] column:0];
[historyCountField setIntValue:[preferences integerForKey:MGMHistoryCount]];
[growlErrors setState:([preferences boolForKey:MGMGrowlErrors] ? NSOnState : NSOffState)];
}
}
return self;
}
- (void)dealloc {
[view release];
[super dealloc];
}
+ (void)setUpToolbarItem:(NSToolbarItem *)theItem {
[theItem setLabel:[self title]];
[theItem setPaletteLabel:[theItem label]];
[theItem setImage:[NSImage imageNamed:@"General"]];
}
+ (NSString *)title {
return @"General";
}
- (NSView *)preferencesView {
return view;
}
- (IBAction)changeDisplay:(id)sender {
int previousDisplay = [preferences integerForKey:MGMDisplay];
int newDisplay = [display selectedRow];
[preferences setInteger:newDisplay forKey:MGMDisplay];
MGMController *controller = [MGMController sharedController];
if (newDisplay==0) {
if (previousDisplay!=1)
[controller setDockHidden:NO];
[controller removeMenu];
} else if (newDisplay==1) {
if (previousDisplay!=0)
[controller setDockHidden:NO];
[controller addMenu];
} else if (newDisplay==2) {
[controller setDockHidden:YES];
[controller addMenu];
}
}
- (IBAction)changeStartup:(id)sender {
BOOL openStartup = ([startup state]==NSOnState);
[preferences setBool:openStartup forKey:MGMStartup];
if (openStartup)
[[MGMLoginItems items] addSelf];
else
[[MGMLoginItems items] removeSelf];
}
- (IBAction)changeUploadName:(id)sender {
[preferences setInteger:[uploadName selectedRow] forKey:MGMUploadName];
}
- (IBAction)changeHistoryCount:(id)sender {
[preferences setInteger:[historyCountField intValue] forKey:MGMHistoryCount];
}
- (IBAction)changeGrowlErrors:(id)sender {
[preferences setBool:([growlErrors state]==NSOnState) forKey:MGMGrowlErrors];
}
@end

View File

@ -0,0 +1,295 @@
//
// RegexKitLite.h
// http://regexkit.sourceforge.net/
// Licensed under the terms of the BSD License, as specified below.
//
/*
Copyright (c) 2008-2010, John Engelhart
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 Zang Industries 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.
*/
#ifdef __OBJC__
#import <Foundation/NSArray.h>
#import <Foundation/NSError.h>
#import <Foundation/NSObjCRuntime.h>
#import <Foundation/NSRange.h>
#import <Foundation/NSString.h>
#endif // __OBJC__
#include <limits.h>
#include <stdint.h>
#include <sys/types.h>
#include <TargetConditionals.h>
#include <AvailabilityMacros.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef REGEXKITLITE_VERSION_DEFINED
#define REGEXKITLITE_VERSION_DEFINED
#define _RKL__STRINGIFY(b) #b
#define _RKL_STRINGIFY(a) _RKL__STRINGIFY(a)
#define _RKL_JOIN_VERSION(a,b) _RKL_STRINGIFY(a##.##b)
#define _RKL_VERSION_STRING(a,b) _RKL_JOIN_VERSION(a,b)
#define REGEXKITLITE_VERSION_MAJOR 4
#define REGEXKITLITE_VERSION_MINOR 0
#define REGEXKITLITE_VERSION_CSTRING _RKL_VERSION_STRING(REGEXKITLITE_VERSION_MAJOR, REGEXKITLITE_VERSION_MINOR)
#define REGEXKITLITE_VERSION_NSSTRING @REGEXKITLITE_VERSION_CSTRING
#endif // REGEXKITLITE_VERSION_DEFINED
#if !defined(RKL_BLOCKS) && defined(NS_BLOCKS_AVAILABLE) && (NS_BLOCKS_AVAILABLE == 1)
#define RKL_BLOCKS 1
#endif
#if defined(RKL_BLOCKS) && (RKL_BLOCKS == 1)
#define _RKL_BLOCKS_ENABLED 1
#endif // defined(RKL_BLOCKS) && (RKL_BLOCKS == 1)
#if defined(_RKL_BLOCKS_ENABLED) && !defined(__BLOCKS__)
#warning RegexKitLite support for Blocks is enabled, but __BLOCKS__ is not defined. This compiler may not support Blocks, in which case the behavior is undefined. This will probably cause numerous compiler errors.
#endif // defined(_RKL_BLOCKS_ENABLED) && !defined(__BLOCKS__)
// For Mac OS X < 10.5.
#ifndef NSINTEGER_DEFINED
#define NSINTEGER_DEFINED
#if defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
typedef long NSInteger;
typedef unsigned long NSUInteger;
#define NSIntegerMin LONG_MIN
#define NSIntegerMax LONG_MAX
#define NSUIntegerMax ULONG_MAX
#else // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
typedef int NSInteger;
typedef unsigned int NSUInteger;
#define NSIntegerMin INT_MIN
#define NSIntegerMax INT_MAX
#define NSUIntegerMax UINT_MAX
#endif // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
#endif // NSINTEGER_DEFINED
#ifndef RKLREGEXOPTIONS_DEFINED
#define RKLREGEXOPTIONS_DEFINED
// These must be identical to their ICU regex counterparts. See http://www.icu-project.org/userguide/regexp.html
enum {
RKLNoOptions = 0,
RKLCaseless = 2,
RKLComments = 4,
RKLDotAll = 32,
RKLMultiline = 8,
RKLUnicodeWordBoundaries = 256
};
typedef uint32_t RKLRegexOptions; // This must be identical to the ICU 'flags' argument type.
#endif // RKLREGEXOPTIONS_DEFINED
#ifndef RKLREGEXENUMERATIONOPTIONS_DEFINED
#define RKLREGEXENUMERATIONOPTIONS_DEFINED
enum {
RKLRegexEnumerationNoOptions = 0UL,
RKLRegexEnumerationCapturedStringsNotRequired = 1UL << 9,
RKLRegexEnumerationReleaseStringReturnedByReplacementBlock = 1UL << 10,
RKLRegexEnumerationFastCapturedStringsXXX = 1UL << 11,
};
typedef NSUInteger RKLRegexEnumerationOptions;
#endif // RKLREGEXENUMERATIONOPTIONS_DEFINED
#ifndef _REGEXKITLITE_H_
#define _REGEXKITLITE_H_
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__APPLE_CC__) && (__APPLE_CC__ >= 5465)
#define RKL_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
#else
#define RKL_DEPRECATED_ATTRIBUTE
#endif
#if defined(NS_REQUIRES_NIL_TERMINATION)
#define RKL_REQUIRES_NIL_TERMINATION NS_REQUIRES_NIL_TERMINATION
#else // defined(NS_REQUIRES_NIL_TERMINATION)
#define RKL_REQUIRES_NIL_TERMINATION
#endif // defined(NS_REQUIRES_NIL_TERMINATION)
// This requires a few levels of rewriting to get the desired results.
#define _RKL_CONCAT_2(c,d) c ## d
#define _RKL_CONCAT(a,b) _RKL_CONCAT_2(a,b)
#ifdef RKL_PREPEND_TO_METHODS
#define RKL_METHOD_PREPEND(x) _RKL_CONCAT(RKL_PREPEND_TO_METHODS, x)
#else // RKL_PREPEND_TO_METHODS
#define RKL_METHOD_PREPEND(x) x
#endif // RKL_PREPEND_TO_METHODS
// If it looks like low memory notifications might be available, add code to register and respond to them.
// This is (should be) harmless if it turns out that this isn't the case, since the notification that we register for,
// UIApplicationDidReceiveMemoryWarningNotification, is dynamically looked up via dlsym().
#if ((defined(TARGET_OS_EMBEDDED) && (TARGET_OS_EMBEDDED != 0)) || (defined(TARGET_OS_IPHONE) && (TARGET_OS_IPHONE != 0))) && (!defined(RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS) || (RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS != 0))
#define RKL_REGISTER_FOR_IPHONE_LOWMEM_NOTIFICATIONS 1
#endif
#ifdef __OBJC__
// NSException exception name.
extern NSString * const RKLICURegexException;
// NSError error domains and user info keys.
extern NSString * const RKLICURegexErrorDomain;
extern NSString * const RKLICURegexEnumerationOptionsErrorKey;
extern NSString * const RKLICURegexErrorCodeErrorKey;
extern NSString * const RKLICURegexErrorNameErrorKey;
extern NSString * const RKLICURegexLineErrorKey;
extern NSString * const RKLICURegexOffsetErrorKey;
extern NSString * const RKLICURegexPreContextErrorKey;
extern NSString * const RKLICURegexPostContextErrorKey;
extern NSString * const RKLICURegexRegexErrorKey;
extern NSString * const RKLICURegexRegexOptionsErrorKey;
extern NSString * const RKLICURegexReplacedCountErrorKey;
extern NSString * const RKLICURegexReplacedStringErrorKey;
extern NSString * const RKLICURegexReplacementStringErrorKey;
extern NSString * const RKLICURegexSubjectRangeErrorKey;
extern NSString * const RKLICURegexSubjectStringErrorKey;
@interface NSString (RegexKitLiteAdditions)
+ (void)RKL_METHOD_PREPEND(clearStringCache);
// Although these are marked as deprecated, a bug in GCC prevents a warning from being issues for + class methods. Filed bug with Apple, #6736857.
+ (NSInteger)RKL_METHOD_PREPEND(captureCountForRegex):(NSString *)regex RKL_DEPRECATED_ATTRIBUTE;
+ (NSInteger)RKL_METHOD_PREPEND(captureCountForRegex):(NSString *)regex options:(RKLRegexOptions)options error:(NSError **)error RKL_DEPRECATED_ATTRIBUTE;
- (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex;
- (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex range:(NSRange)range;
- (NSArray *)RKL_METHOD_PREPEND(componentsSeparatedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error;
- (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex;
- (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex inRange:(NSRange)range;
- (BOOL)RKL_METHOD_PREPEND(isMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error;
- (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex;
- (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex capture:(NSInteger)capture;
- (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex inRange:(NSRange)range;
- (NSRange)RKL_METHOD_PREPEND(rangeOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range capture:(NSInteger)capture error:(NSError **)error;
- (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex;
- (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex capture:(NSInteger)capture;
- (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex inRange:(NSRange)range;
- (NSString *)RKL_METHOD_PREPEND(stringByMatching):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range capture:(NSInteger)capture error:(NSError **)error;
- (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement;
- (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange;
- (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error;
//// >= 3.0
- (NSInteger)RKL_METHOD_PREPEND(captureCount);
- (NSInteger)RKL_METHOD_PREPEND(captureCountWithOptions):(RKLRegexOptions)options error:(NSError **)error;
- (BOOL)RKL_METHOD_PREPEND(isRegexValid);
- (BOOL)RKL_METHOD_PREPEND(isRegexValidWithOptions):(RKLRegexOptions)options error:(NSError **)error;
- (void)RKL_METHOD_PREPEND(flushCachedRegexData);
- (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex;
- (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex capture:(NSInteger)capture;
- (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex range:(NSRange)range;
- (NSArray *)RKL_METHOD_PREPEND(componentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range capture:(NSInteger)capture error:(NSError **)error;
- (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex;
- (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex range:(NSRange)range;
- (NSArray *)RKL_METHOD_PREPEND(captureComponentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error;
- (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex;
- (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex range:(NSRange)range;
- (NSArray *)RKL_METHOD_PREPEND(arrayOfCaptureComponentsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error;
//// >= 4.0
- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex range:(NSRange)range withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withFirstKey:(id)firstKey arguments:(va_list)varArgsList;
- (NSArray *)RKL_METHOD_PREPEND(arrayOfDictionariesByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeys:(id *)keys forCaptures:(int *)captures count:(NSUInteger)count;
- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex range:(NSRange)range withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeysAndCaptures:(id)firstKey, ... RKL_REQUIRES_NIL_TERMINATION;
- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withFirstKey:(id)firstKey arguments:(va_list)varArgsList;
- (NSDictionary *)RKL_METHOD_PREPEND(dictionaryByMatchingRegex):(NSString *)regex options:(RKLRegexOptions)options range:(NSRange)range error:(NSError **)error withKeys:(id *)keys forCaptures:(int *)captures count:(NSUInteger)count;
#ifdef _RKL_BLOCKS_ENABLED
- (BOOL)RKL_METHOD_PREPEND(enumerateStringsMatchedByRegex):(NSString *)regex usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
- (BOOL)RKL_METHOD_PREPEND(enumerateStringsMatchedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
- (BOOL)RKL_METHOD_PREPEND(enumerateStringsSeparatedByRegex):(NSString *)regex usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
- (BOOL)RKL_METHOD_PREPEND(enumerateStringsSeparatedByRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(void (^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
- (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
- (NSString *)RKL_METHOD_PREPEND(stringByReplacingOccurrencesOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
#endif // _RKL_BLOCKS_ENABLED
@end
@interface NSMutableString (RegexKitLiteAdditions)
- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement;
- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement range:(NSRange)searchRange;
- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex withString:(NSString *)replacement options:(RKLRegexOptions)options range:(NSRange)searchRange error:(NSError **)error;
//// >= 4.0
#ifdef _RKL_BLOCKS_ENABLED
- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
- (NSInteger)RKL_METHOD_PREPEND(replaceOccurrencesOfRegex):(NSString *)regex options:(RKLRegexOptions)options inRange:(NSRange)range error:(NSError **)error enumerationOptions:(RKLRegexEnumerationOptions)enumerationOptions usingBlock:(NSString *(^)(NSInteger captureCount, NSString * const capturedStrings[captureCount], const NSRange capturedRanges[captureCount], volatile BOOL * const stop))block;
#endif // _RKL_BLOCKS_ENABLED
@end
#endif // __OBJC__
#endif // _REGEXKITLITE_H_
#ifdef __cplusplus
} // extern "C"
#endif

File diff suppressed because it is too large Load Diff

14
Classes/CocoaShare/main.m Normal file
View File

@ -0,0 +1,14 @@
//
// main.m
// CocoaShare
//
// Created by James on 1/15/11.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). All rights reserved. http://mrgeckosmedia.com/
//
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}

View File

@ -0,0 +1,7 @@
//
// Prefix header for all source files of the 'CocoaShare' target in the 'CocoaShare' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif

View File

@ -0,0 +1,26 @@
//
// DBAccountInfo.h
// DropboxSDK
//
// Created by Brian Smith on 5/3/10.
// Copyright 2010 Dropbox, Inc. All rights reserved.
//
#import "DBQuota.h"
@interface DBAccountInfo : NSObject <NSCoding> {
NSString* country;
NSString* displayName;
DBQuota* quota;
NSString* userId;
NSString* referralLink;
}
- (id)initWithDictionary:(NSDictionary*)dict;
- (NSString *)country;
- (NSString *)displayName;
- (DBQuota *)quota;
- (NSString *)userId;
- (NSString *)referralLink;
@end

View File

@ -0,0 +1,70 @@
//
// 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];
}
- (NSString *)country {
return country;
}
- (NSString *)displayName {
return displayName;
}
- (DBQuota *)quota {
return quota;
}
- (NSString *)userId {
return userId;
}
- (NSString *)referralLink {
return 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

View File

@ -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;

View File

@ -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";

View File

@ -0,0 +1,38 @@
//
// DBMetadata.h
// DropboxSDK
//
// Created by Brian Smith on 5/3/10.
// Copyright 2010 Dropbox, Inc. All rights reserved.
//
@interface DBMetadata : NSObject <NSCoding> {
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;
- (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;
@end

View File

@ -0,0 +1,150 @@
//
// 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 (long long i=0; i<[subfileDicts count]; i++) {
DBMetadata* subfile = [[DBMetadata alloc] initWithDictionary:[subfileDicts objectAtIndex:i]];
[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];
}
- (BOOL)thumbnailExists {
return thumbnailExists;
}
- (long long)totalBytes {
return totalBytes;
}
- (NSDate *)lastModifiedDate {
return lastModifiedDate;
}
- (NSString *)path {
return path;
}
- (BOOL)isDirectory {
return isDirectory;
}
- (NSArray *)contents {
return contents;
}
- (NSString *)hash {
return hash;
}
- (NSString *)humanReadableSize {
return humanReadableSize;
}
- (NSString *)root {
return root;
}
- (NSString *)icon {
return icon;
}
- (long long)revision {
return revision;
}
- (BOOL)isDeleted {
return 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

View File

@ -0,0 +1,21 @@
//
// DBQuota.h
// DropboxSDK
//
// Created by Brian Smith on 5/3/10.
// Copyright 2010 Dropbox, Inc. All rights reserved.
//
@interface DBQuota : NSObject <NSCoding> {
long long normalConsumedBytes;
long long sharedConsumedBytes;
long long totalBytes;
}
- (id)initWithDictionary:(NSDictionary*)dict;
- (long long)normalConsumedBytes;
- (long long)sharedConsumedBytes;
- (long long)totalConsumedBytes;
- (long long)totalBytes;
@end

View File

@ -0,0 +1,56 @@
//
// 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];
}
- (long long)normalConsumedBytes {
return normalConsumedBytes;
}
- (long long)sharedConsumedBytes {
return sharedConsumedBytes;
}
- (long long)totalConsumedBytes {
return normalConsumedBytes + sharedConsumedBytes;
}
- (long long)totalBytes {
return totalBytes;
}
#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

View File

@ -0,0 +1,75 @@
//
// 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;
int bytesDownloaded;
float downloadProgress;
float 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<DBNetworkRequestDelegate>)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;
- (void)setFailureSelector:(SEL)theSelector; // To send failure events to a different selector set this
- (SEL)failureSelector;
- (void)setDownloadProgressSelector:(SEL)theSelector; // To receive download progress events set this
- (SEL)downloadProgressSelector;
- (void)setUploadProgressSelector:(SEL)theSelector; // To receive upload progress events set this
- (SEL)uploadProgressSelector;
- (void)setResultFilename:(NSString *)theName; // The file to put the HTTP body in, otherwise body is stored in resultData
- (NSString *)resultFilename;
- (void)setUserInfo:(NSDictionary *)theInfo;
- (NSDictionary *)userInfo;
- (NSURLRequest *)request;
- (NSHTTPURLResponse *)response;
- (int)statusCode;
- (float)downloadProgress;
- (float)uploadProgress;
- (NSData *)resultData;
- (NSString *)resultString;
- (NSObject *)resultJSON;
- (NSError *)error;
@end
@protocol DBNetworkRequestDelegate
- (void)networkRequestStarted;
- (void)networkRequestStopped;
@end

View File

@ -0,0 +1,285 @@
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
//
// 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<DBNetworkRequestDelegate>)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];
}
- (void)setFailureSelector:(SEL)theSelector {
failureSelector = theSelector;
}
- (SEL)failureSelector {
return failureSelector;
}
- (void)setDownloadProgressSelector:(SEL)theSelector {
downloadProgressSelector = theSelector;
}
- (SEL)downloadProgressSelector {
return downloadProgressSelector;
}
- (void)setUploadProgressSelector:(SEL)theSelector {
uploadProgressSelector = theSelector;
}
- (SEL)uploadProgressSelector {
return uploadProgressSelector;
}
- (void)setResultFilename:(NSString *)theName {
[resultFilename release];
resultFilename = [theName retain];
}
- (NSString *)resultFilename {
return resultFilename;
}
- (void)setUserInfo:(NSDictionary *)theInfo {
[userInfo release];
userInfo = [theInfo retain];
}
- (NSDictionary *)userInfo {
return userInfo;
}
- (NSURLRequest *)request {
return request;
}
- (NSHTTPURLResponse *)response {
return response;
}
- (int)statusCode {
return [response statusCode];
}
- (float)downloadProgress {
return downloadProgress;
}
- (float)uploadProgress {
return uploadProgress;
}
- (NSData *)resultData {
return resultData;
}
- (NSString *)resultString {
return [[[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding] autorelease];
}
- (NSObject *)resultJSON {
return [[self resultString] JSONValue];
}
- (NSError *)error {
return error;
}
- (void)cancel {
[urlConnection cancel];
target = nil;
if (tempFilename) {
[fileHandle closeFile];
NSError* rmError;
NSFileManager *manager = [NSFileManager defaultManager];
BOOL result = NO;
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
result = [manager removeFileAtPath:tempFilename handler:nil];
else
result = [manager removeItemAtPath:tempFilename error:&rmError];
if (!result) {
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 *manager = [NSFileManager defaultManager];
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
[manager removeFileAtPath:tempFilename handler:nil];
else
[manager 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];
int contentLength = [[[response allHeaderFields] objectForKey:@"Content-Length"] intValue];
downloadProgress = (float)bytesDownloaded / (float)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 *manager = [NSFileManager defaultManager];
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
[manager removeFileAtPath:resultFilename handler:nil];
else
[manager removeItemAtPath:resultFilename error:nil];
NSError* moveError;
BOOL result = NO;
if ([manager respondsToSelector:@selector(movePath:toPath:handler:)])
result = [manager movePath:tempFilename toPath:resultFilename handler:nil];
else
result = [manager moveItemAtPath:tempFilename toPath:resultFilename error:&moveError];
if (!result) {
NSLog(@"DBRequest#connectionDidFinishLoading: error moving temp file to desired location: %@",
[moveError localizedDescription]);
error = [[NSError alloc] initWithDomain:moveError.domain code:moveError.code userInfo: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:userInfo];
bytesDownloaded = 0;
downloadProgress = 0;
uploadProgress = 0;
if (tempFilename) {
NSFileManager *manager = [NSFileManager defaultManager];
NSError* removeError;
BOOL result = NO;
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
result = [manager removeFileAtPath:tempFilename handler:nil];
else
result = [manager removeItemAtPath:tempFilename error:&removeError];
if (!result) {
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:(int)bytesWritten
totalBytesWritten:(int)totalBytesWritten
totalBytesExpectedToWrite:(int)totalBytesExpectedToWrite {
uploadProgress = (float)totalBytesWritten / (float)totalBytesExpectedToWrite;
if (uploadProgressSelector) {
[target performSelector:uploadProgressSelector withObject:self];
}
}
@end

View File

@ -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<DBRestClientDelegate> 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;
- (void)setDelegate:(id)theDelegate;
- (id<DBRestClientDelegate>)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 <NSObject>
@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:(float)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:(float)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:(float)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

View File

@ -0,0 +1,846 @@
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
//
// 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 NSString (Addons)
- (NSString *)replace:(NSString *)targetString with:(NSString *)replaceString;
@end
@implementation NSString (Addons)
- (NSString *)replace:(NSString *)targetString with:(NSString *)replaceString {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSMutableString *temp = [NSMutableString new];
NSRange replaceRange = NSMakeRange(0, [self length]);
NSRange rangeInOriginalString = replaceRange;
int replaced = 0;
while (1) {
NSRange rangeToCopy;
NSRange foundRange = [self rangeOfString:targetString options:0 range:rangeInOriginalString];
if (foundRange.length == 0) break;
rangeToCopy = NSMakeRange(rangeInOriginalString.location, foundRange.location - rangeInOriginalString.location);
[temp appendString:[self substringWithRange:rangeToCopy]];
[temp appendString:replaceString];
rangeInOriginalString.length -= NSMaxRange(foundRange) -
rangeInOriginalString.location;
rangeInOriginalString.location = NSMaxRange(foundRange);
replaced++;
if (replaced % 100 == 0) {
[pool drain];
pool = [NSAutoreleasePool new];
}
}
if (rangeInOriginalString.length > 0) [temp appendString:[self substringWithRange:rangeInOriginalString]];
[pool drain];
return [temp autorelease];
}
@end
@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 {
NSArray *requestsArray = [requests allObjects];
for (int i=0; i<[requestsArray count]; i++) {
[[requestsArray objectAtIndex:i] cancel];
}
[requests release];
for (int i=0; i<[[loadRequests allValues] count]; i++) {
[[[loadRequests allValues] objectAtIndex:i] cancel];
}
[loadRequests release];
[session release];
[root release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<DBRestClientDelegate>)delegate {
return 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 {
[NSThread detachNewThreadSelector:@selector(parseMetadataWithRequest:) toTarget:self 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 *manager = [NSFileManager defaultManager];
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
[manager removeFileAtPath:tempFilePath handler:nil];
else
[manager 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 *manager = [NSFileManager defaultManager];
if ([manager respondsToSelector:@selector(removeFileAtPath:handler:)])
[manager removeFileAtPath:tempFilePath handler:nil];
else
[manager 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 replace:@";" with:@"-"];
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

View File

@ -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<DBSessionDelegate> 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;
- (MPOAuthCredentialConcreteStore *)credentialStore;
- (void)setDelegate:(id)theDelegate;
- (id<DBSessionDelegate>)delegate;
@end
@protocol DBSessionDelegate
- (void)sessionDidReceiveAuthorizationFailure:(DBSession*)session;
@end

View File

@ -0,0 +1,123 @@
//
// 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 DBSession* 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];
}
- (MPOAuthCredentialConcreteStore *)credentialStore {
return credentialStore;
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<DBSessionDelegate>)delegate {
return 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 nil;//[[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

View File

@ -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"

View File

@ -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"

View File

@ -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 <Foundation/Foundation.h>
/**
@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

View File

@ -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

View File

@ -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 <Foundation/Foundation.h>
/**
@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

View File

@ -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

View File

@ -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 <Foundation/Foundation.h>
#import "SBJsonParser.h"
#import "SBJsonWriter.h"
/**
@brief Facade for SBJsonWriter/SBJsonParser.
Requests are forwarded to instances of SBJsonWriter and SBJsonParser.
*/
@interface SBJSON : SBJsonBase <SBJsonParser, SBJsonWriter> {
@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

View File

@ -0,0 +1,213 @@
/*
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
- (unsigned int)maxDepth {
return [jsonParser maxDepth];
}
- (void)setMaxDepth:(unsigned int)d {
[jsonWriter setMaxDepth:d];
[jsonParser setMaxDepth: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

View File

@ -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 <Foundation/Foundation.h>
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
unsigned int 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.
*/
- (void)setMaxDepth:(unsigned int)theDepth;
- (unsigned int)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.
*/
- (NSArray *)errorTrace;
/// @internal for use in subclasses to add errors to the stack trace
- (void)addErrorWithCode:(unsigned int)code description:(NSString*)str;
/// @internal for use in subclasess to clear the error before a new parsing attempt
- (void)clearErrorTrace;
@end

View File

@ -0,0 +1,84 @@
/*
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
- (id)init {
self = [super init];
if (self)
maxDepth = 512;
return self;
}
- (void)dealloc {
[errorTrace release];
[super dealloc];
}
- (void)setMaxDepth:(unsigned int)theDepth {
maxDepth = theDepth;
}
- (unsigned int)maxDepth {
return maxDepth;
}
- (NSArray *)errorTrace {
return errorTrace;
}
- (void)addErrorWithCode:(unsigned int)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

View File

@ -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 <Foundation/Foundation.h>
#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 <SBJsonParser> {
@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

View File

@ -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

View File

@ -0,0 +1,131 @@
/*
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 <Foundation/Foundation.h>
#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.
*/
- (void)setHumanReadable:(BOOL)isHumanReadable;
- (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.
*/
- (void)setSortKeys:(BOOL)willShortKeys;
- (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 <SBJsonWriter> {
@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

View File

@ -0,0 +1,248 @@
/*
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: @"\"\\"];
}
- (void)setHumanReadable:(BOOL)isHumanReadable {
humanReadable = isHumanReadable;
}
- (BOOL)humanReadable {
return humanReadable;
}
- (void)setSortKeys:(BOOL)willShortKeys {
sortKeys = willShortKeys;
}
- (BOOL)sortKeys {
return sortKeys;
}
/**
@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 (int i=0; i<[fragment count]; i++) {
id value = [fragment objectAtIndex:i];
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 (sortKeys)
keys = [keys sortedArrayUsingSelector:@selector(compare:)];
for (int i=0; i<[keys count]; i++) {
id value = [keys objectAtIndex:i];
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 {
unsigned int length = [fragment length];
for (unsigned int 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

View File

@ -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 <math.h>
#include <string.h>
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);
}

View File

@ -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 <stdlib.h>
#include <stdbool.h>
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);

View File

@ -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

View File

@ -0,0 +1,20 @@
//
// MPOAuth.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.13.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MPOAuth/MPOAuthAPI.h>
#import <MPOAuth/MPOAuthAPIRequestLoader.h>
#import <MPOAuth/MPOAuthAuthenticationMethod.h>
#import <MPOAuth/MPOAuthAuthenticationMethodOAuth.h>
#import <MPOAuth/MPOAuthCredentialStore.h>
#import <MPOAuth/MPOAuthParameterFactory.h>
#import <MPOAuth/MPOAuthConnection.h>
#import <MPOAuth/MPOAuthURLRequest.h>
#import <MPOAuth/MPOAuthURLResponse.h>

View File

@ -0,0 +1,94 @@
//
// MPOAuthAPI.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.05.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
#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 <MPOAuthAPIInternalClient> {
@private
id <MPOAuthCredentialStore, MPOAuthParameterFactory> credentials;
NSURL *baseURL;
NSURL *authenticationURL;
MPOAuthAuthenticationMethod *authenticationMethod;
MPOAuthSignatureScheme signatureScheme;
NSMutableArray *activeLoaders;
MPOAuthAuthenticationState oauthAuthenticationState;
}
- (void)setCredentials:(id)theCredentials;
- (id<MPOAuthCredentialStore,MPOAuthParameterFactory>)credentials;
- (void)setBaseURL:(NSURL *)theURL;
- (NSURL *)baseURL;
- (void)setAuthenticationURL:(NSURL *)theURL;
- (NSURL *)authenticationURL;
- (void)setAuthenticationMethod:(MPOAuthAuthenticationMethod *)theMethod;
- (MPOAuthAuthenticationMethod *)authenticationMethod;
- (void)setSignatureScheme:(MPOAuthSignatureScheme)theScheme;
- (MPOAuthSignatureScheme)signatureScheme;
- (void)setAuthenticationState:(MPOAuthAuthenticationState)theState;
- (MPOAuthAuthenticationState)authenticationState;
- (void)setActiveLoaders:(NSMutableArray *)theLoaders;
- (NSMutableArray *)activeLoaders;
- (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

View File

@ -0,0 +1,253 @@
//
// 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 ()
- (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 setAuthenticationURL:inAuthURL];
[self setBaseURL:inBaseURL];
[self setAuthenticationState:MPOAuthAuthenticationStateUnauthenticated];
credentials = [[MPOAuthCredentialConcreteStore alloc] initWithCredentials:inCredentials forBaseURL:inBaseURL withAuthenticationURL:inAuthURL];
[self setAuthenticationMethod:[[MPOAuthAuthenticationMethod alloc] initWithAPI:self forURL:inAuthURL]];
[self setSignatureScheme:MPOAuthSignatureSchemeHMACSHA1];
activeLoaders = [[NSMutableArray alloc] initWithCapacity:10];
if (aFlag) {
[self authenticate];
}
}
return self;
}
- (oneway void)dealloc {
[credentials release];
[baseURL release];
[authenticationURL release];
[authenticationMethod release];
[activeLoaders release];
[super dealloc];
}
- (void)setCredentials:(id)theCredentials {
credentials = theCredentials;
}
- (id<MPOAuthCredentialStore,MPOAuthParameterFactory>)credentials {
return credentials;
}
- (void)setBaseURL:(NSURL *)theURL {
[baseURL release];
baseURL = [theURL retain];
}
- (NSURL *)baseURL {
return baseURL;
}
- (void)setAuthenticationURL:(NSURL *)theURL {
[authenticationURL release];
authenticationURL = [theURL retain];
}
- (NSURL *)authenticationURL {
return authenticationURL;
}
- (void)setAuthenticationMethod:(MPOAuthAuthenticationMethod *)theMethod {
[authenticationMethod release];
authenticationMethod = [theMethod retain];
}
- (MPOAuthAuthenticationMethod *)authenticationMethod {
return authenticationMethod;
}
- (void)setSignatureScheme:(MPOAuthSignatureScheme)theScheme {
signatureScheme = theScheme;
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];
}
- (MPOAuthSignatureScheme)signatureScheme {
return signatureScheme;
}
- (void)setAuthenticationState:(MPOAuthAuthenticationState)theState {
oauthAuthenticationState = theState;
}
- (MPOAuthAuthenticationState)authenticationState {
return oauthAuthenticationState;
}
- (void)setActiveLoaders:(NSMutableArray *)theLoaders {
[activeLoaders release];
activeLoaders = [theLoaders retain];
}
- (NSMutableArray *)activeLoaders {
return activeLoaders;
}
#pragma mark -
- (void)authenticate {
NSAssert([credentials consumerKey], @"A Consumer Key is required for use of OAuth.");
[authenticationMethod authenticate];
}
- (BOOL)isAuthenticated {
return ([self authenticationState] == MPOAuthAuthenticationStateAuthenticated);
}
#pragma mark -
- (void)performMethod:(NSString *)inMethod withTarget:(id)inTarget andAction:(SEL)inAction {
[self performMethod:inMethod atURL: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 = credentials;
loader.target = inTarget;
loader.action = inAction ? inAction : @selector(_performedLoad:receivingData:);
[loader loadSynchronously:NO];
// [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 = credentials;
loader.target = inTarget;
loader.action = inAction ? inAction : @selector(_performedLoad:receivingData:);
[loader loadSynchronously:NO];
// [activeLoaders addObject:loader];
[loader release];
[aRequest release];
}
- (NSData *)dataForMethod:(NSString *)inMethod {
return [self dataForURL:baseURL andMethod:inMethod withParameters:nil];
}
- (NSData *)dataForMethod:(NSString *)inMethod withParameters:(NSArray *)inParameters {
return [self dataForURL: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 = credentials;
[loader loadSynchronously:YES];
[loader autorelease];
[aRequest release];
return loader.data;
}
#pragma mark -
- (id)credentialNamed:(NSString *)inCredentialName {
return [credentials credentialNamed:inCredentialName];
}
- (void)setCredential:(id)inCredential withName:(NSString *)inName {
[(MPOAuthCredentialConcreteStore *)credentials setCredential:inCredential withName:inName];
}
- (void)removeCredentialNamed:(NSString *)inName {
[(MPOAuthCredentialConcreteStore *)credentials removeCredentialNamed:inName];
}
- (void)discardCredentials {
[credentials discardOAuthCredentials];
[self setAuthenticationState:MPOAuthAuthenticationStateUnauthenticated];
}
#pragma mark -
#pragma mark - Private APIs -
- (void)_performedLoad:(MPOAuthAPIRequestLoader *)inLoader receivingData:(NSData *)inData {
// NSLog(@"loaded %@, and got %@", inLoader, inData);
}
@end

View File

@ -0,0 +1,53 @@
//
// MPOAuthAPIRequestLoader.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.05.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
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 *data;
NSString *responseString;
NSError *error;
id target;
SEL action;
}
- (void)setCredentials:(id)theCredentials;
- (id<MPOAuthCredentialStore,MPOAuthParameterFactory>)credentials;
- (void)setOauthRequest:(MPOAuthURLRequest *)theRequest;
- (MPOAuthURLRequest *)oauthRequest;
- (void)setOauthResponse:(MPOAuthURLResponse *)theResponse;
- (MPOAuthURLResponse *)oauthResponse;
- (NSData *)data;
- (NSString *)responseString;
- (void)setTarget:(id)theTarget;
- (id)target;
- (void)setAction:(SEL)theAction;
- (SEL)action;
- (id)initWithURL:(NSURL *)inURL;
- (id)initWithRequest:(MPOAuthURLRequest *)inRequest;
- (void)loadSynchronously:(BOOL)inSynchronous;
@end

View File

@ -0,0 +1,231 @@
//
// 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 MPOAuthAPIRequestLoader ()
- (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 setOauthRequest:inRequest];
data = [[NSMutableData alloc] init];
}
return self;
}
- (oneway void)dealloc {
[credentials release];
[oauthRequest release];
[oauthResponse release];
[data release];
[responseString release];
[super dealloc];
}
- (void)setCredentials:(id)theCredentials {
[credentials release];
credentials = [theCredentials retain];
}
- (id<MPOAuthCredentialStore,MPOAuthParameterFactory>)credentials {
return credentials;
}
- (void)setOauthRequest:(MPOAuthURLRequest *)theRequest {
[oauthRequest release];
oauthRequest = [theRequest retain];
}
- (MPOAuthURLRequest *)oauthRequest {
return oauthRequest;
}
- (void)setOauthResponse:(MPOAuthURLResponse *)theResponse {
[oauthResponse release];
oauthResponse = [theResponse retain];
}
- (MPOAuthURLResponse *)oauthResponse {
if (oauthResponse==nil)
oauthResponse = [[MPOAuthURLResponse alloc] init];
return oauthResponse;
}
- (NSData *)data {
return data;
}
- (NSString *)responseString {
if (responseString==nil)
responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return responseString;
}
- (void)setTarget:(id)theTarget {
target = theTarget;
}
- (id)target {
return target;
}
- (void)setAction:(SEL)theAction {
action = theAction;
}
- (SEL)action {
return action;
}
#pragma mark -
- (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:oauthRequest delegate:self credentials:credentials];
} else {
MPOAuthURLResponse *theOAuthResponse = nil;
data = [[MPOAuthConnection sendSynchronousRequest:oauthRequest usingCredentials:credentials returningResponse:&theOAuthResponse error:nil] retain];
[self setOauthResponse:theOAuthResponse];
[self _interrogateResponseForOAuthData];
}
}
#pragma mark -
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)theError {
MPLog(@"%p: [%@ %@] %@, %@", self, NSStringFromClass([self class]), NSStringFromSelector(_cmd), connection, theError);
if ([target respondsToSelector:@selector(loader:didFailWithError:)]) {
[target performSelector: @selector(loader:didFailWithError:) withObject: self withObject: theError];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[[self oauthResponse] setResponse:response];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
MPLog(@"%@", NSStringFromSelector(_cmd));
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData {
[data appendData:theData];
}
- (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:data];
} else {
[target performSelector:action withObject:[oauthRequest url] withObject:responseString];
}
}
}
#pragma mark -
- (void)_interrogateResponseForOAuthData {
NSString *response = responseString;
NSDictionary *foundParameters = nil;
int status = [(NSHTTPURLResponse *)[[self oauthResponse] response] statusCode];
if ([response length] > 5 && [[response substringToIndex:5] isEqualToString:@"oauth"]) {
foundParameters = [MPURLRequestParameter parameterDictionaryFromString:response];
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 ([credentials requestToken] && ![credentials accessToken]) {
[credentials setRequestToken:nil];
[credentials setRequestTokenSecret:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:MPOAuthNotificationRequestTokenRejected
object:nil
userInfo:foundParameters];
} else if ([credentials accessToken] && ![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 (![credentials requestToken] && ![credentials accessToken]) {
[credentials setRequestToken:aParameterValue];
[credentials setRequestTokenSecret:[foundParameters objectForKey:@"oauth_token_secret"]];
[[NSNotificationCenter defaultCenter] postNotificationName:MPOAuthNotificationRequestTokenReceived
object:nil
userInfo:foundParameters];
} else if (![credentials accessToken] && [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 ([credentials accessToken] && ![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

View File

@ -0,0 +1,32 @@
//
// MPOAuthAuthenticationMethod.h
// MPOAuthConnection
//
// Created by Karl Adam on 09.12.19.
// Copyright 2009 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
extern NSString * const MPOAuthAccessTokenURLKey;
@class MPOAuthAPI;
@interface MPOAuthAuthenticationMethod : NSObject {
MPOAuthAPI *oauthAPI;
NSURL *oauthGetAccessTokenURL;
NSTimer *refreshTimer;
}
- (void)setOauthAPI:(MPOAuthAPI *)theAPI;
- (MPOAuthAPI *)oauthAPI;
- (void)setOauthGetAccessTokenURL:(NSURL *)theURL;
- (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

View File

@ -0,0 +1,140 @@
//
// 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 ()
+ (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]) {
oauthAPI = inAPI;
}
return self;
}
- (oneway void)dealloc {
[oauthGetAccessTokenURL release];
[refreshTimer invalidate];
[refreshTimer release];
refreshTimer = nil;
[super dealloc];
}
- (void)setOauthAPI:(MPOAuthAPI *)theAPI {
oauthAPI = theAPI;
}
- (MPOAuthAPI *)oauthAPI {
return oauthAPI;
}
- (void)setOauthGetAccessTokenURL:(NSURL *)theURL {
[oauthGetAccessTokenURL release];
oauthGetAccessTokenURL = [theURL retain];
}
- (NSURL *)oauthGetAccessTokenURL {
return oauthGetAccessTokenURL;
}
#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];
NSEnumerator *enumerator = [oauthConfigDictionary keyEnumerator];
NSString *domainString = nil;
while (domainString = [enumerator nextObject]) {
if ([inBaseURL domainMatches:domainString]) {
NSDictionary *oauthConfig = [oauthConfigDictionary objectForKey:domainString];
NSArray *requestedMethods = [oauthConfig objectForKey:@"MPOAuthAuthenticationPreferredMethods"];
NSString *requestedMethod = nil;
for (int i=0; i<[requestedMethods count]; i++) {
requestedMethod = [requestedMethods objectAtIndex:i];
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 (refreshTimer==nil && inTimeInterval > 0.0) {
refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:inTimeInterval target:self selector:@selector(_automaticallyRefreshAccessToken:) userInfo:nil repeats:YES] retain];
}
}
- (void)refreshAccessToken {
MPURLRequestParameter *sessionHandleParameter = nil;
MPOAuthCredentialConcreteStore *credentials = (MPOAuthCredentialConcreteStore *)[oauthAPI credentials];
if (credentials.sessionHandle) {
sessionHandleParameter = [[MPURLRequestParameter alloc] init];
sessionHandleParameter.name = @"oauth_session_handle";
sessionHandleParameter.value = credentials.sessionHandle;
}
[oauthAPI performMethod:nil
atURL:oauthGetAccessTokenURL
withParameters:sessionHandleParameter ? [NSArray arrayWithObject:sessionHandleParameter] : nil
withTarget:nil
andAction:nil];
[sessionHandleParameter release];
}
#pragma mark -
- (void)_automaticallyRefreshAccessToken:(NSTimer *)inTimer {
[self refreshAccessToken];
}
@end

View File

@ -0,0 +1,50 @@
//
// MPOAuthAuthenticationMethodOAuth.h
// MPOAuthConnection
//
// Created by Karl Adam on 09.12.19.
// Copyright 2009 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPOAuthAuthenticationMethod.h"
#import "MPOAuthAPI.h"
#import "MPOAuthAPIRequestLoader.h"
extern NSString * const MPOAuthNotificationRequestTokenReceived;
extern NSString * const MPOAuthNotificationRequestTokenRejected;
@protocol MPOAuthAuthenticationMethodOAuthDelegate;
@interface MPOAuthAuthenticationMethodOAuth : MPOAuthAuthenticationMethod <MPOAuthAPIInternalClient> {
NSURL *oauthRequestTokenURL;
NSURL *oauthAuthorizeTokenURL;
BOOL oauth10aModeActive;
id<MPOAuthAuthenticationMethodOAuthDelegate> delegate;
}
- (void)setDelegate:(id)theDelegate;
- (id<MPOAuthAuthenticationMethodOAuthDelegate>)delegate;
- (void)setOauthRequestTokenURL:(NSURL *)theURL;
- (NSURL *)oauthRequestTokenURL;
- (void)setOauthAuthorizeTokenURL:(NSURL *)theURL;
- (NSURL *)oauthAuthorizeTokenURL;
- (void)setOauth10aModeActive:(BOOL)isActive;
- (BOOL)oauth10aModeActive;
- (void)authenticate;
@end
@protocol MPOAuthAuthenticationMethodOAuthDelegate <NSObject>
- (NSURL *)callbackURLForCompletedUserAuthorization;
- (BOOL)automaticallyRequestAuthenticationFromURL:(NSURL *)inAuthURL withCallbackURL:(NSURL *)inCallbackURL;
@optional
- (NSString *)oauthVerifierForCompletedUserAuthorization;
- (void)authenticationDidFailWithError:(NSError *)error;
@end

View File

@ -0,0 +1,231 @@
//
// 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 MPOAuthAuthenticationMethodOAuth ()
- (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 setOauthRequestTokenURL:[NSURL URLWithString:[inConfig objectForKey:MPOAuthRequestTokenURLKey]]];
[self setOauthAuthorizeTokenURL:[NSURL URLWithString:[inConfig objectForKey:MPOAuthUserAuthorizationURLKey]]];
[self setOauthGetAccessTokenURL:[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 {
[oauthRequestTokenURL release];
[oauthAuthorizeTokenURL release];
[super dealloc];
}
- (void)setDelegate:(id)theDelegate {
delegate = theDelegate;
}
- (id<MPOAuthAuthenticationMethodOAuthDelegate>)delegate {
return delegate;
}
- (void)setOauthRequestTokenURL:(NSURL *)theURL {
[oauthRequestTokenURL release];
oauthRequestTokenURL = [theURL retain];
}
- (NSURL *)oauthRequestTokenURL {
return oauthRequestTokenURL;
}
- (void)setOauthAuthorizeTokenURL:(NSURL *)theURL {
[oauthAuthorizeTokenURL release];
oauthAuthorizeTokenURL = [theURL retain];
}
- (NSURL *)oauthAuthorizeTokenURL {
return oauthAuthorizeTokenURL;
}
- (void)setOauth10aModeActive:(BOOL)isActive {
oauth10aModeActive = isActive;
}
- (BOOL)oauth10aModeActive {
return oauth10aModeActive;
}
#pragma mark -
- (void)authenticate {
id <MPOAuthCredentialStore> 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] floatForKey:MPOAuthTokenRefreshDateDefaultsKey];
NSDate *tokenExpiryDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expiryDateInterval];
if ([tokenExpiryDate compare:[NSDate date]] == NSOrderedAscending) {
[self refreshAccessToken];
}
}
}
- (void)_authenticationRequestForRequestToken {
if (oauthRequestTokenURL) {
MPLog(@"--> Performing Request Token Request: %@", oauthRequestTokenURL);
// Append the oauth_callbackUrl parameter for requesting the request token
MPURLRequestParameter *callbackParameter = nil;
if (delegate && [delegate respondsToSelector: @selector(callbackURLForCompletedUserAuthorization)]) {
NSURL *callbackURL = [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: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] : oauthAuthorizeTokenURL;
NSURL *callbackURL = nil;
if (!oauth10aModeActive) {
callbackURL = [delegate respondsToSelector:@selector(callbackURLForCompletedUserAuthorization)] ? [delegate callbackURLForCompletedUserAuthorization] : nil;
}
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys: [oauthResponseParameters objectForKey: @"oauth_token"], @"oauth_token",
callbackURL, @"oauth_callback",
nil];
userAuthURL = [userAuthURL urlByAddingParameterDictionary:parameters];
BOOL delegateWantsToBeInvolved = [delegate respondsToSelector:@selector(automaticallyRequestAuthenticationFromURL:withCallbackURL:)];
if (!delegateWantsToBeInvolved || (delegateWantsToBeInvolved && [delegate automaticallyRequestAuthenticationFromURL:userAuthURL withCallbackURL:callbackURL])) {
MPLog(@"--> Automatically Performing User Auth Request: %@", userAuthURL);
[self _authenticationRequestForUserPermissionsConfirmationAtURL:userAuthURL];
}
}
- (void)loader:(MPOAuthAPIRequestLoader *)inLoader didFailWithError:(NSError *)error {
if ([delegate respondsToSelector:@selector(authenticationDidFailWithError:)]) {
[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 (delegate && [delegate respondsToSelector: @selector(oauthVerifierForCompletedUserAuthorization)]) {
MPURLRequestParameter *verifierParameter = nil;
NSString *verifier = [delegate oauthVerifierForCompletedUserAuthorization];
if (verifier) {
verifierParameter = [[[MPURLRequestParameter alloc] initWithName:@"oauth_verifier" andValue:verifier] autorelease];
params = [NSArray arrayWithObject:verifierParameter];
}
}
if (oauthGetAccessTokenURL) {
MPLog(@"--> Performing Access Token Request: %@", oauthGetAccessTokenURL);
[[self oauthAPI] performMethod:nil atURL:oauthGetAccessTokenURL withParameters:params withTarget:self andAction:nil];
}
}
#pragma mark -
- (void)_requestTokenReceived:(NSNotification *)inNotification {
if ([[inNotification userInfo] objectForKey:@"oauth_callback_confirmed"]) {
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];
}
[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] setFloat:[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

View File

@ -0,0 +1,28 @@
//
// MPOAuthConnection.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.05.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
@protocol MPOAuthCredentialStore;
@protocol MPOAuthParameterFactory;
@class MPOAuthURLRequest;
@class MPOAuthURLResponse;
@class MPOAuthCredentialConcreteStore;
@interface MPOAuthConnection : NSURLConnection {
@private
MPOAuthCredentialConcreteStore *credentials;
}
- (id<MPOAuthCredentialStore,MPOAuthParameterFactory>)credentials;
+ (MPOAuthConnection *)connectionWithRequest:(MPOAuthURLRequest *)inRequest delegate:(id)inDelegate credentials:(NSObject <MPOAuthCredentialStore, MPOAuthParameterFactory> *)inCredentials;
+ (NSData *)sendSynchronousRequest:(MPOAuthURLRequest *)inRequest usingCredentials:(NSObject <MPOAuthCredentialStore, MPOAuthParameterFactory> *)inCredentials returningResponse:(MPOAuthURLResponse **)outResponse error:(NSError **)inError;
- (id)initWithRequest:(MPOAuthURLRequest *)inRequest delegate:(id)inDelegate credentials:(NSObject <MPOAuthCredentialStore, MPOAuthParameterFactory> *)inCredentials;
@end

View File

@ -0,0 +1,54 @@
//
// 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"
@implementation MPOAuthConnection
+ (MPOAuthConnection *)connectionWithRequest:(MPOAuthURLRequest *)inRequest delegate:(id)inDelegate credentials:(NSObject <MPOAuthCredentialStore, MPOAuthParameterFactory> *)inCredentials {
MPOAuthConnection *aConnection = [[MPOAuthConnection alloc] initWithRequest:inRequest delegate:inDelegate credentials:inCredentials];
return [aConnection autorelease];
}
+ (NSData *)sendSynchronousRequest:(MPOAuthURLRequest *)inRequest usingCredentials:(NSObject <MPOAuthCredentialStore, MPOAuthParameterFactory> *)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 setResponse:urlResponse];
*outResponse = oauthResponse;
return responseData;
}
- (id)initWithRequest:(MPOAuthURLRequest *)inRequest delegate:(id)inDelegate credentials:(NSObject <MPOAuthCredentialStore, MPOAuthParameterFactory> *)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];
}
- (id<MPOAuthCredentialStore,MPOAuthParameterFactory>)credentials {
return credentials;
}
#pragma mark -
@end

View File

@ -0,0 +1,90 @@
//
// MPOAuthCredentialConcreteStore+TokenAdditionsMac.m
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.13.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import "MPOAuthCredentialConcreteStore+KeychainAdditions.h"
#import <Security/Security.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,
'oaut',
kSecAuthenticationTypeDefault,
(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

View File

@ -0,0 +1,18 @@
//
// MPOAuthCredentialConcreteStore+TokenAdditionsMac.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.13.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPOAuthCredentialConcreteStore.h"
@interface MPOAuthCredentialConcreteStore (KeychainAdditions)
- (void)addToKeychainUsingName:(NSString *)inName andValue:(NSString *)inValue;
- (NSString *)findValueFromKeychainUsingName:(NSString *)inName;
- (void)removeValueFromKeychainUsingName:(NSString *)inName;
@end

View File

@ -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 <Security/Security.h>
#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

View File

@ -0,0 +1,48 @@
//
// MPOAuthCredentialConcreteStore.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.11.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "MPOAuthCredentialStore.h"
#import "MPOAuthParameterFactory.h"
@interface MPOAuthCredentialConcreteStore : NSObject <MPOAuthCredentialStore, MPOAuthParameterFactory> {
NSMutableDictionary *store;
NSURL *baseURL;
NSURL *authenticationURL;
}
- (void)setStore:(NSMutableDictionary *)theStore;
- (NSMutableDictionary *)store;
- (void)setBaseURL:(NSURL *)theURL;
- (NSURL *)baseURL;
- (void)setAuthenticationURL:(NSURL *)theURL;
- (NSURL *)authenticationURL;
- (NSString *)tokenSecret;
- (NSString *)signingKey;
- (void)setRequestToken:(NSString *)theToken;
- (NSString *)requestToken;
- (void)setRequestTokenSecret:(NSString *)theSecret;
- (NSString *)requestTokenSecret;
- (void)setAccessToken:(NSString *)theToken;
- (NSString *)accessToken;
- (void)setAccessTokenSecret:(NSString *)theSecret;
- (NSString *)accessTokenSecret;
- (void)setSessionHandle:(NSString *)theHandle;
- (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

View File

@ -0,0 +1,295 @@
//
// 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;
@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 setBaseURL:inBaseURL];
[self setAuthenticationURL:inAuthenticationURL];
}
return self;
}
- (oneway void)dealloc {
[store release];
[baseURL release];
[authenticationURL release];
[super dealloc];
}
- (void)setStore:(NSMutableDictionary *)theStore {
[store release];
store = [theStore retain];
}
- (NSMutableDictionary *)store {
return store;
}
- (void)setBaseURL:(NSURL *)theURL {
[baseURL release];
baseURL = [theURL retain];
}
- (NSURL *)baseURL {
return baseURL;
}
- (void)setAuthenticationURL:(NSURL *)theURL {
[authenticationURL release];
authenticationURL = [theURL retain];
}
- (NSURL *)authenticationURL {
return authenticationURL;
}
#pragma mark -
- (NSString *)consumerKey {
return [store objectForKey:kMPOAuthCredentialConsumerKey];
}
- (NSString *)consumerSecret {
return [store objectForKey:kMPOAuthCredentialConsumerSecret];
}
- (NSString *)username {
return [store objectForKey:kMPOAuthCredentialUsername];
}
- (NSString *)password {
return [store objectForKey:kMPOAuthCredentialPassword];
}
- (NSString *)requestToken {
return [store objectForKey:kMPOAuthCredentialRequestToken];
}
- (void)setRequestToken:(NSString *)inToken {
if (inToken) {
[store setObject:inToken forKey:kMPOAuthCredentialRequestToken];
} else {
[store removeObjectForKey:kMPOAuthCredentialRequestToken];
[self removeValueFromKeychainUsingName:kMPOAuthCredentialRequestToken];
}
}
- (NSString *)requestTokenSecret {
return [store objectForKey:kMPOAuthCredentialRequestTokenSecret];
}
- (void)setRequestTokenSecret:(NSString *)inTokenSecret {
if (inTokenSecret) {
[store setObject:inTokenSecret forKey:kMPOAuthCredentialRequestTokenSecret];
} else {
[store removeObjectForKey:kMPOAuthCredentialRequestTokenSecret];
[self removeValueFromKeychainUsingName:kMPOAuthCredentialRequestTokenSecret];
}
}
- (NSString *)accessToken {
return [store objectForKey:kMPOAuthCredentialAccessToken];
}
- (void)setAccessToken:(NSString *)inToken {
if (inToken) {
[store setObject:inToken forKey:kMPOAuthCredentialAccessToken];
} else {
[store removeObjectForKey:kMPOAuthCredentialAccessToken];
[self removeValueFromKeychainUsingName:kMPOAuthCredentialAccessToken];
}
}
- (NSString *)accessTokenSecret {
return [store objectForKey:kMPOAuthCredentialAccessTokenSecret];
}
- (void)setAccessTokenSecret:(NSString *)inTokenSecret {
if (inTokenSecret) {
[store setObject:inTokenSecret forKey:kMPOAuthCredentialAccessTokenSecret];
} else {
[store removeObjectForKey:kMPOAuthCredentialAccessTokenSecret];
[self removeValueFromKeychainUsingName:kMPOAuthCredentialAccessTokenSecret];
}
}
- (NSString *)sessionHandle {
return [store objectForKey:kMPOAuthCredentialSessionHandle];
}
- (void)setSessionHandle:(NSString *)inSessionHandle {
if (inSessionHandle) {
[store setObject:inSessionHandle forKey:kMPOAuthCredentialSessionHandle];
} else {
[store removeObjectForKey:kMPOAuthCredentialSessionHandle];
[self removeValueFromKeychainUsingName:kMPOAuthCredentialSessionHandle];
}
}
#pragma mark -
- (NSString *)credentialNamed:(NSString *)inCredentialName {
return [store objectForKey:inCredentialName];
}
- (void)setCredential:(id)inCredential withName:(NSString *)inName {
[store setObject:inCredential forKey:inName];
[self addToKeychainUsingName:inName andValue:inCredential];
}
- (void)removeCredentialNamed:(NSString *)inName {
[store removeObjectForKey:inName];
[self removeValueFromKeychainUsingName:inName];
}
- (void)discardOAuthCredentials {
[self setRequestToken:nil];
[self setRequestTokenSecret:nil];
[self setAccessToken:nil];
[self setAccessTokenSecret:nil];
[self setSessionHandle: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 [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 {
[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 = [store objectForKey:@"versionParameter"];
if (!versionParameter) {
versionParameter = [[MPURLRequestParameter alloc] init];
versionParameter.name = @"oauth_version";
versionParameter.value = @"1.0";
[versionParameter autorelease];
}
return versionParameter;
}
@end

View File

@ -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 <NSObject>
- (NSString *)consumerKey;
- (NSString *)consumerSecret;
- (NSString *)username;
- (NSString *)password;
- (NSString *)requestToken;
- (NSString *)requestTokenSecret;
- (NSString *)accessToken;
- (NSString *)accessTokenSecret;
- (NSString *)credentialNamed:(NSString *)inCredentialName;
- (void)discardOAuthCredentials;
@end

View File

@ -0,0 +1,29 @@
//
// MPOAuthParameterFactory.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.06.
// Copyright 2008 matrixPointer. All rights reserved.
//
extern NSString *kMPOAuthSignatureMethod;
@class MPURLRequestParameter;
@protocol MPOAuthParameterFactory <NSObject>
- (void)setSignatureMethod:(NSString *)theMethod;
- (NSString *)signatureMethod;
- (NSString *)signingKey;
- (NSString *)timestamp;
- (NSArray *)oauthParameters;
- (MPURLRequestParameter *)oauthConsumerKeyParameter;
- (MPURLRequestParameter *)oauthTokenParameter;
- (MPURLRequestParameter *)oauthSignatureMethodParameter;
- (MPURLRequestParameter *)oauthTimestampParameter;
- (MPURLRequestParameter *)oauthNonceParameter;
- (MPURLRequestParameter *)oauthVersionParameter;
@end

View File

@ -0,0 +1,28 @@
//
// MPOAuthSignatureParameter.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.07.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
#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

View File

@ -0,0 +1,94 @@
//
// 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 <openssl/evp.h>
#include <openssl/hmac.h>
#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];
OpenSSL_add_all_algorithms();
unsigned char outbuf[SHA_DIGEST_LENGTH];
unsigned int templen;
HMAC_CTX ctx;
const EVP_MD *digest = EVP_sha1();
if(!digest) {
NSLog(@"cannot get digest with name SHA1");
return nil;
}
HMAC_CTX_init(&ctx);
HMAC_Init(&ctx, [secretData bytes], [secretData length], digest);
HMAC_Update(&ctx, [textData bytes], [textData length]);
HMAC_Final(&ctx, outbuf, &templen);
HMAC_CTX_cleanup(&ctx);
//Base64 Encoding
char base64Result[32];
size_t theResultLength = 32;
Base64EncodeData(outbuf, 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 setName:@"oauth_signature"];
[self setValue: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 setName:@"oauth_signature"];
[self setValue:[MPOAuthSignatureParameter HMAC_SHA1SignatureForText:signatureBaseString usingSecret:inSecret]];
}
return self;
}
- (oneway void)dealloc {
[super dealloc];
}
@end

View File

@ -0,0 +1,36 @@
//
// MPOAuthURLRequest.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.05.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPOAuthURLRequest : NSObject {
@private
NSURL *url;
NSString *HTTPMethod;
NSURLRequest *urlRequest;
NSMutableArray *parameters;
}
- (void)setURL:(NSURL *)theURL;
- (NSURL *)url;
- (void)setHTTPMethod:(NSString *)theMethod;
- (NSString *)HTTPMethod;
- (void)setURLRequest:(NSURLRequest *)theRequest;
- (NSURLRequest *)urlRequest;
- (void)setParameters:(NSMutableArray *)theParameters;
- (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

View File

@ -0,0 +1,119 @@
//
// 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"
@implementation MPOAuthURLRequest
- (id)initWithURL:(NSURL *)inURL andParameters:(NSArray *)inParameters {
if (self = [super init]) {
url = [inURL retain];
parameters = inParameters ? [inParameters mutableCopy] : [[NSMutableArray alloc] initWithCapacity:10];
[self setHTTPMethod:@"GET"];
}
return self;
}
- (id)initWithURLRequest:(NSURLRequest *)inRequest {
if (self = [super init]) {
url = [[[inRequest URL] urlByRemovingQuery] retain];
parameters = [[MPURLRequestParameter parametersFromString:[[inRequest URL] query]] mutableCopy];
[self setHTTPMethod:[inRequest HTTPMethod]];
}
return self;
}
- (oneway void)dealloc {
[url release];
[HTTPMethod release];
[urlRequest release];
[parameters release];
[super dealloc];
}
- (void)setURL:(NSURL *)theURL {
[url release];
url = [theURL retain];
}
- (NSURL *)url {
return url;
}
- (void)setHTTPMethod:(NSString *)theMethod {
[HTTPMethod release];
HTTPMethod = [theMethod retain];
}
- (NSString *)HTTPMethod {
return HTTPMethod;
}
- (void)setURLRequest:(NSURLRequest *)theRequest {
[urlRequest release];
urlRequest = [theRequest retain];
}
- (NSURLRequest *)urlRequest {
return urlRequest;
}
- (void)setParameters:(NSMutableArray *)theParameters {
[parameters release];
parameters = [theParameters retain];
}
- (NSMutableArray *)parameters {
return parameters;
}
#pragma mark -
- (NSMutableURLRequest*)urlRequestSignedWithSecret:(NSString *)inSecret usingMethod:(NSString *)inScheme {
[parameters sortUsingSelector:@selector(compare:)];
NSMutableURLRequest *aRequest = [[NSMutableURLRequest alloc] init];
NSMutableString *parameterString = [[NSMutableString alloc] initWithString:[MPURLRequestParameter parameterStringForParameters:parameters]];
MPOAuthSignatureParameter *signatureParameter = [[MPOAuthSignatureParameter alloc] initWithText:parameterString andSecret:inSecret forRequest:self usingMethod:inScheme];
[parameterString appendFormat:@"&%@", [signatureParameter URLEncodedParameterString]];
[aRequest setHTTPMethod:HTTPMethod];
if ([[self HTTPMethod] isEqualToString:@"GET"] && [parameters count]) {
NSString *urlString = [NSString stringWithFormat:@"%@?%@", [url absoluteString], parameterString];
MPLog( @"urlString - %@", urlString);
[aRequest setURL:[NSURL URLWithString:urlString]];
} else if ([[self HTTPMethod] isEqualToString:@"POST"]) {
NSData *postData = [parameterString dataUsingEncoding:NSUTF8StringEncoding];
MPLog(@"urlString - %@", url);
MPLog(@"postDataString - %@", parameterString);
[aRequest setURL: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", HTTPMethod];
}
[parameterString release];
[signatureParameter release];
urlRequest = [aRequest retain];
[aRequest release];
return aRequest;
}
#pragma mark -
- (void)addParameters:(NSArray *)inParameters {
[parameters addObjectsFromArray:inParameters];
}
@end

View File

@ -0,0 +1,21 @@
//
// MPOAuthURLResponse.h
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.05.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPOAuthURLResponse : NSObject {
NSURLResponse *urlResponse;
NSDictionary *oauthParameters;
}
- (void)setResponse:(NSURLResponse *)theResponse;
- (NSURLResponse *)response;
- (void)setOauthParameters:(NSDictionary *)theParameters;
- (NSDictionary *)oauthParameters;
@end

View File

@ -0,0 +1,41 @@
//
// MPOAuthURLResponse.m
// MPOAuthConnection
//
// Created by Karl Adam on 08.12.05.
// Copyright 2008 matrixPointer. All rights reserved.
//
#import "MPOAuthURLResponse.h"
@implementation MPOAuthURLResponse
- (id)init {
if (self = [super init]) {
}
return self;
}
- (void)dealloc {
[urlResponse release];
[oauthParameters release];
[super dealloc];
}
- (void)setResponse:(NSURLResponse *)theResponse {
[urlResponse release];
urlResponse = [theResponse retain];
}
- (NSURLResponse *)response {
return urlResponse;
}
- (void)setOauthParameters:(NSDictionary *)theParameters {
[oauthParameters release];
oauthParameters = [theParameters retain];
}
- (NSDictionary *)oauthParameters {
return oauthParameters;
}
@end

Some files were not shown because too many files have changed in this diff Show More