├── Example ├── Classes │ ├── TestAppDelegate.h │ ├── TestAppDelegate.m │ ├── TestViewController.h │ └── TestViewController.m ├── MainWindow.xib ├── Test-Info.plist ├── Test.xcodeproj │ └── project.pbxproj ├── TestViewController.xib ├── Test_Prefix.pch └── main.m ├── README.textile └── Sources ├── English.lproj └── Twitter.strings ├── French.lproj └── Twitter.strings ├── TwitterAuthenticator.h ├── TwitterAuthenticator.m ├── TwitterClouds.png ├── TwitterComposeViewController.h ├── TwitterComposeViewController.m ├── TwitterComposeViewController.xib ├── TwitterConsumer.h ├── TwitterConsumer.m ├── TwitterLoginViewController.h ├── TwitterLoginViewController.m ├── TwitterLoginViewController.xib ├── TwitterRequest.h ├── TwitterRequest.m ├── TwitterToken.h ├── TwitterToken.m ├── TwitterTweetPoster.h ├── TwitterTweetPoster.m ├── TwitterUtils.h └── TwitterUtils.m /Example/Classes/TestAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestAppDelegate.h 3 | // Test 4 | // 5 | // Created by Stefan Arentz on 10-05-05. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class TestViewController; 12 | 13 | @interface TestAppDelegate : NSObject { 14 | UIWindow *window; 15 | TestViewController *viewController; 16 | } 17 | 18 | @property (nonatomic, retain) IBOutlet UIWindow *window; 19 | @property (nonatomic, retain) IBOutlet TestViewController *viewController; 20 | 21 | @end 22 | 23 | -------------------------------------------------------------------------------- /Example/Classes/TestAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestAppDelegate.m 3 | // Test 4 | // 5 | // Created by Stefan Arentz on 10-05-05. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import "TestAppDelegate.h" 10 | #import "TestViewController.h" 11 | 12 | @implementation TestAppDelegate 13 | 14 | @synthesize window; 15 | @synthesize viewController; 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | 20 | // Override point for customization after app launch 21 | [window addSubview:viewController.view]; 22 | [window makeKeyAndVisible]; 23 | 24 | return YES; 25 | } 26 | 27 | 28 | - (void)dealloc { 29 | [viewController release]; 30 | [window release]; 31 | [super dealloc]; 32 | } 33 | 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Example/Classes/TestViewController.h: -------------------------------------------------------------------------------- 1 | // TestViewController.h 2 | 3 | #import 4 | 5 | #import "TwitterLoginViewController.h" 6 | #import "TwitterComposeViewController.h" 7 | 8 | @class TwitterConsumer; 9 | @class TwitterToken; 10 | 11 | @interface TestViewController : UIViewController { 12 | @private 13 | TwitterConsumer* _consumer; 14 | TwitterToken* _token; 15 | } 16 | 17 | - (IBAction) share; 18 | - (IBAction) reset; 19 | 20 | @end -------------------------------------------------------------------------------- /Example/Classes/TestViewController.m: -------------------------------------------------------------------------------- 1 | // TestViewController.m 2 | 3 | #import "TwitterToken.h" 4 | #import "TwitterConsumer.h" 5 | 6 | #import "TwitterLoginViewController.h" 7 | #import "TwitterComposeViewController.h" 8 | 9 | #import "TestViewController.h" 10 | 11 | @implementation TestViewController 12 | 13 | - (void) viewDidLoad 14 | { 15 | // Replace the key and secret with your own 16 | 17 | _consumer = [[TwitterConsumer alloc] initWithKey: @"KEY" secret: @"SECRET"]; 18 | 19 | // Try to get the token from the keychain. If it does not exist then we will have to show the login dialog 20 | // first. In a real application you should store the token in the user's keychain! 21 | 22 | NSData* tokenData = [[NSUserDefaults standardUserDefaults] dataForKey: @"Token"]; 23 | if (tokenData != nil) 24 | { 25 | _token = (TwitterToken*) [[NSKeyedUnarchiver unarchiveObjectWithData: tokenData] retain]; 26 | } 27 | } 28 | 29 | - (void) openTweetComposer 30 | { 31 | TwitterComposeViewController* twitterComposeViewController = [[TwitterComposeViewController new] autorelease]; 32 | if (twitterComposeViewController != nil) 33 | { 34 | twitterComposeViewController.consumer = _consumer; 35 | twitterComposeViewController.token = _token; 36 | twitterComposeViewController.message = @"I like Cheese"; 37 | twitterComposeViewController.delegate = self; 38 | 39 | UINavigationController* navigationController = [[[UINavigationController alloc] initWithRootViewController: twitterComposeViewController] autorelease]; 40 | if (navigationController != nil) { 41 | [self presentModalViewController: navigationController animated: YES]; 42 | } 43 | } 44 | } 45 | 46 | - (IBAction) share 47 | { 48 | if (_token == nil) 49 | { 50 | TwitterLoginViewController* twitterLoginViewController = [[TwitterLoginViewController new] autorelease]; 51 | if (twitterLoginViewController != nil) 52 | { 53 | twitterLoginViewController.consumer = _consumer; 54 | twitterLoginViewController.delegate = self; 55 | 56 | UINavigationController* navigationController = [[[UINavigationController alloc] initWithRootViewController: twitterLoginViewController] autorelease]; 57 | if (navigationController != nil) { 58 | [self presentModalViewController: navigationController animated: YES]; 59 | } 60 | } 61 | } 62 | else 63 | { 64 | [self openTweetComposer]; 65 | } 66 | } 67 | 68 | - (IBAction) reset 69 | { 70 | [[NSUserDefaults standardUserDefaults] removeObjectForKey: @"Token"]; 71 | [[NSUserDefaults standardUserDefaults] synchronize]; 72 | 73 | [_token release]; 74 | _token = nil; 75 | } 76 | 77 | #pragma mark - 78 | 79 | - (void) twitterLoginViewControllerDidCancel: (TwitterLoginViewController*) twitterLoginViewController 80 | { 81 | [twitterLoginViewController dismissModalViewControllerAnimated: YES]; 82 | } 83 | 84 | - (void) twitterLoginViewController: (TwitterLoginViewController*) twitterLoginViewController didSucceedWithToken: (TwitterToken*) token 85 | { 86 | _token = [token retain]; 87 | 88 | // Save the token to the user defaults 89 | 90 | [[NSUserDefaults standardUserDefaults] setObject: [NSKeyedArchiver archivedDataWithRootObject: _token] forKey: @"Token"]; 91 | [[NSUserDefaults standardUserDefaults] synchronize]; 92 | 93 | // Open the tweet composer and dismiss the login screen 94 | 95 | TwitterComposeViewController* twitterComposeViewController = [[TwitterComposeViewController new] autorelease]; 96 | if (twitterComposeViewController != nil) 97 | { 98 | twitterComposeViewController.consumer = _consumer; 99 | twitterComposeViewController.token = _token; 100 | twitterComposeViewController.message = @"I like Cheese"; 101 | twitterComposeViewController.delegate = self; 102 | 103 | [twitterLoginViewController.navigationController pushViewController: twitterComposeViewController animated: YES]; 104 | } 105 | } 106 | 107 | - (void) twitterLoginViewController: (TwitterLoginViewController*) twitterLoginViewController didFailWithError: (NSError*) error 108 | { 109 | NSLog(@"twitterLoginViewController: %@ didFailWithError: %@", self, error); 110 | } 111 | 112 | #pragma mark - 113 | 114 | - (void) twitterComposeViewControllerDidCancel: (TwitterComposeViewController*) twitterComposeViewController 115 | { 116 | [twitterComposeViewController dismissModalViewControllerAnimated: YES]; 117 | } 118 | 119 | - (void) twitterComposeViewControllerDidSucceed: (TwitterComposeViewController*) twitterComposeViewController 120 | { 121 | [twitterComposeViewController dismissModalViewControllerAnimated: YES]; 122 | } 123 | 124 | - (void) twitterComposeViewController: (TwitterComposeViewController*) twitterComposeViewController didFailWithError: (NSError*) error 125 | { 126 | [twitterComposeViewController dismissModalViewControllerAnimated: YES]; 127 | } 128 | 129 | #pragma mark - 130 | 131 | - (void) dealloc 132 | { 133 | [_consumer release]; 134 | [_token release]; 135 | [super dealloc]; 136 | } 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /Example/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 800 5 | 10D540 6 | 760 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 81 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | IBCocoaTouchFramework 42 | 43 | 44 | TestViewController 45 | 46 | IBCocoaTouchFramework 47 | 48 | 49 | 50 | 292 51 | {320, 480} 52 | 53 | 1 54 | MSAxIDEAA 55 | 56 | NO 57 | NO 58 | 59 | IBCocoaTouchFramework 60 | YES 61 | 62 | 63 | 64 | 65 | YES 66 | 67 | 68 | delegate 69 | 70 | 71 | 72 | 4 73 | 74 | 75 | 76 | viewController 77 | 78 | 79 | 80 | 11 81 | 82 | 83 | 84 | window 85 | 86 | 87 | 88 | 14 89 | 90 | 91 | 92 | 93 | YES 94 | 95 | 0 96 | 97 | 98 | 99 | 100 | 101 | -1 102 | 103 | 104 | File's Owner 105 | 106 | 107 | 3 108 | 109 | 110 | Test App Delegate 111 | 112 | 113 | -2 114 | 115 | 116 | 117 | 118 | 10 119 | 120 | 121 | 122 | 123 | 12 124 | 125 | 126 | 127 | 128 | 129 | 130 | YES 131 | 132 | YES 133 | -1.CustomClassName 134 | -2.CustomClassName 135 | 10.CustomClassName 136 | 10.IBEditorWindowLastContentRect 137 | 10.IBPluginDependency 138 | 12.IBEditorWindowLastContentRect 139 | 12.IBPluginDependency 140 | 3.CustomClassName 141 | 3.IBPluginDependency 142 | 143 | 144 | YES 145 | UIApplication 146 | UIResponder 147 | TestViewController 148 | {{234, 376}, {320, 480}} 149 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 150 | {{525, 346}, {320, 480}} 151 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 152 | TestAppDelegate 153 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 154 | 155 | 156 | 157 | YES 158 | 159 | 160 | YES 161 | 162 | 163 | 164 | 165 | YES 166 | 167 | 168 | YES 169 | 170 | 171 | 172 | 14 173 | 174 | 175 | 176 | YES 177 | 178 | TestAppDelegate 179 | NSObject 180 | 181 | YES 182 | 183 | YES 184 | viewController 185 | window 186 | 187 | 188 | YES 189 | TestViewController 190 | UIWindow 191 | 192 | 193 | 194 | IBProjectSource 195 | Classes/TestAppDelegate.h 196 | 197 | 198 | 199 | TestAppDelegate 200 | NSObject 201 | 202 | IBUserSource 203 | 204 | 205 | 206 | 207 | TestViewController 208 | UIViewController 209 | 210 | IBProjectSource 211 | Classes/TestViewController.h 212 | 213 | 214 | 215 | 216 | 0 217 | IBCocoaTouchFramework 218 | 219 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 220 | 221 | 222 | YES 223 | Test.xcodeproj 224 | 3 225 | 81 226 | 227 | 228 | -------------------------------------------------------------------------------- /Example/Test-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.yourcompany.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | 30 | 31 | -------------------------------------------------------------------------------- /Example/Test.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D3623260D0F684500981E51 /* TestAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* TestAppDelegate.m */; }; 11 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 12 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 13 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 14 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; 15 | 2899E5220DE3E06400AC0155 /* TestViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2899E5210DE3E06400AC0155 /* TestViewController.xib */; }; 16 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; 17 | 28D7ACF80DDB3853001CB0EB /* TestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* TestViewController.m */; }; 18 | F83FEDFE11D7FC7200C6411C /* Twitter.strings in Resources */ = {isa = PBXBuildFile; fileRef = F83FEDFC11D7FC7200C6411C /* Twitter.strings */; }; 19 | F8733C491193C50700680E83 /* TwitterClouds.png in Resources */ = {isa = PBXBuildFile; fileRef = F8733C481193C50700680E83 /* TwitterClouds.png */; }; 20 | F8BC11F7119270670065FCB5 /* TwitterComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BC11E6119270670065FCB5 /* TwitterComposeViewController.m */; }; 21 | F8BC11F8119270670065FCB5 /* TwitterComposeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F8BC11E7119270670065FCB5 /* TwitterComposeViewController.xib */; }; 22 | F8BC11F9119270670065FCB5 /* TwitterAuthenticator.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BC11E9119270670065FCB5 /* TwitterAuthenticator.m */; }; 23 | F8BC11FA119270670065FCB5 /* TwitterConsumer.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BC11EB119270670065FCB5 /* TwitterConsumer.m */; }; 24 | F8BC11FB119270670065FCB5 /* TwitterLoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BC11ED119270670065FCB5 /* TwitterLoginViewController.m */; }; 25 | F8BC11FC119270670065FCB5 /* TwitterLoginViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F8BC11EE119270670065FCB5 /* TwitterLoginViewController.xib */; }; 26 | F8BC11FD119270670065FCB5 /* TwitterRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BC11F0119270670065FCB5 /* TwitterRequest.m */; }; 27 | F8BC11FE119270670065FCB5 /* TwitterToken.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BC11F2119270670065FCB5 /* TwitterToken.m */; }; 28 | F8BC11FF119270670065FCB5 /* TwitterTweetPoster.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BC11F4119270670065FCB5 /* TwitterTweetPoster.m */; }; 29 | F8BC1200119270670065FCB5 /* TwitterUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = F8BC11F6119270670065FCB5 /* TwitterUtils.m */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 34 | 1D3623240D0F684500981E51 /* TestAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestAppDelegate.h; sourceTree = ""; }; 35 | 1D3623250D0F684500981E51 /* TestAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestAppDelegate.m; sourceTree = ""; }; 36 | 1D6058910D05DD3D006BFB54 /* Test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Test.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 38 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 39 | 2899E5210DE3E06400AC0155 /* TestViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = TestViewController.xib; path = ../TestViewController.xib; sourceTree = ""; }; 40 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 41 | 28D7ACF60DDB3853001CB0EB /* TestViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestViewController.h; sourceTree = ""; }; 42 | 28D7ACF70DDB3853001CB0EB /* TestViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestViewController.m; sourceTree = ""; }; 43 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 44 | 32CA4F630368D1EE00C91783 /* Test_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Test_Prefix.pch; sourceTree = ""; }; 45 | 8D1107310486CEB800E47090 /* Test-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Test-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; 46 | F83FEDFD11D7FC7200C6411C /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = ../Sources/English.lproj/Twitter.strings; sourceTree = SOURCE_ROOT; }; 47 | F83FEDFF11D7FC7C00C6411C /* French */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = French; path = ../Sources/French.lproj/Twitter.strings; sourceTree = SOURCE_ROOT; }; 48 | F8733C481193C50700680E83 /* TwitterClouds.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = TwitterClouds.png; path = ../Sources/TwitterClouds.png; sourceTree = SOURCE_ROOT; }; 49 | F8BC11E5119270670065FCB5 /* TwitterComposeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwitterComposeViewController.h; path = ../Sources/TwitterComposeViewController.h; sourceTree = SOURCE_ROOT; }; 50 | F8BC11E6119270670065FCB5 /* TwitterComposeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TwitterComposeViewController.m; path = ../Sources/TwitterComposeViewController.m; sourceTree = SOURCE_ROOT; }; 51 | F8BC11E7119270670065FCB5 /* TwitterComposeViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = TwitterComposeViewController.xib; path = ../Sources/TwitterComposeViewController.xib; sourceTree = SOURCE_ROOT; }; 52 | F8BC11E8119270670065FCB5 /* TwitterAuthenticator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwitterAuthenticator.h; path = ../Sources/TwitterAuthenticator.h; sourceTree = SOURCE_ROOT; }; 53 | F8BC11E9119270670065FCB5 /* TwitterAuthenticator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TwitterAuthenticator.m; path = ../Sources/TwitterAuthenticator.m; sourceTree = SOURCE_ROOT; }; 54 | F8BC11EA119270670065FCB5 /* TwitterConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwitterConsumer.h; path = ../Sources/TwitterConsumer.h; sourceTree = SOURCE_ROOT; }; 55 | F8BC11EB119270670065FCB5 /* TwitterConsumer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TwitterConsumer.m; path = ../Sources/TwitterConsumer.m; sourceTree = SOURCE_ROOT; }; 56 | F8BC11EC119270670065FCB5 /* TwitterLoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwitterLoginViewController.h; path = ../Sources/TwitterLoginViewController.h; sourceTree = SOURCE_ROOT; }; 57 | F8BC11ED119270670065FCB5 /* TwitterLoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TwitterLoginViewController.m; path = ../Sources/TwitterLoginViewController.m; sourceTree = SOURCE_ROOT; }; 58 | F8BC11EE119270670065FCB5 /* TwitterLoginViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = TwitterLoginViewController.xib; path = ../Sources/TwitterLoginViewController.xib; sourceTree = SOURCE_ROOT; }; 59 | F8BC11EF119270670065FCB5 /* TwitterRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwitterRequest.h; path = ../Sources/TwitterRequest.h; sourceTree = SOURCE_ROOT; }; 60 | F8BC11F0119270670065FCB5 /* TwitterRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TwitterRequest.m; path = ../Sources/TwitterRequest.m; sourceTree = SOURCE_ROOT; }; 61 | F8BC11F1119270670065FCB5 /* TwitterToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwitterToken.h; path = ../Sources/TwitterToken.h; sourceTree = SOURCE_ROOT; }; 62 | F8BC11F2119270670065FCB5 /* TwitterToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TwitterToken.m; path = ../Sources/TwitterToken.m; sourceTree = SOURCE_ROOT; }; 63 | F8BC11F3119270670065FCB5 /* TwitterTweetPoster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwitterTweetPoster.h; path = ../Sources/TwitterTweetPoster.h; sourceTree = SOURCE_ROOT; }; 64 | F8BC11F4119270670065FCB5 /* TwitterTweetPoster.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TwitterTweetPoster.m; path = ../Sources/TwitterTweetPoster.m; sourceTree = SOURCE_ROOT; }; 65 | F8BC11F5119270670065FCB5 /* TwitterUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TwitterUtils.h; path = ../Sources/TwitterUtils.h; sourceTree = SOURCE_ROOT; }; 66 | F8BC11F6119270670065FCB5 /* TwitterUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TwitterUtils.m; path = ../Sources/TwitterUtils.m; sourceTree = SOURCE_ROOT; }; 67 | /* End PBXFileReference section */ 68 | 69 | /* Begin PBXFrameworksBuildPhase section */ 70 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 71 | isa = PBXFrameworksBuildPhase; 72 | buildActionMask = 2147483647; 73 | files = ( 74 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 75 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 76 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | /* End PBXFrameworksBuildPhase section */ 81 | 82 | /* Begin PBXGroup section */ 83 | 080E96DDFE201D6D7F000001 /* Classes */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 1D3623240D0F684500981E51 /* TestAppDelegate.h */, 87 | 1D3623250D0F684500981E51 /* TestAppDelegate.m */, 88 | 28D7ACF60DDB3853001CB0EB /* TestViewController.h */, 89 | 28D7ACF70DDB3853001CB0EB /* TestViewController.m */, 90 | 2899E5210DE3E06400AC0155 /* TestViewController.xib */, 91 | ); 92 | path = Classes; 93 | sourceTree = ""; 94 | }; 95 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 1D6058910D05DD3D006BFB54 /* Test.app */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | F8BC11E1119270590065FCB5 /* Twitter Sources */, 107 | 080E96DDFE201D6D7F000001 /* Classes */, 108 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 109 | 29B97317FDCFA39411CA2CEA /* Resources */, 110 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 111 | 19C28FACFE9D520D11CA2CBB /* Products */, 112 | ); 113 | name = CustomTemplate; 114 | sourceTree = ""; 115 | }; 116 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 32CA4F630368D1EE00C91783 /* Test_Prefix.pch */, 120 | 29B97316FDCFA39411CA2CEA /* main.m */, 121 | ); 122 | name = "Other Sources"; 123 | sourceTree = ""; 124 | }; 125 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | F83FEDFC11D7FC7200C6411C /* Twitter.strings */, 129 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */, 130 | 8D1107310486CEB800E47090 /* Test-Info.plist */, 131 | ); 132 | name = Resources; 133 | sourceTree = ""; 134 | }; 135 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 139 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 140 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */, 141 | ); 142 | name = Frameworks; 143 | sourceTree = ""; 144 | }; 145 | F8BC11E1119270590065FCB5 /* Twitter Sources */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | F8BC11E5119270670065FCB5 /* TwitterComposeViewController.h */, 149 | F8BC11E6119270670065FCB5 /* TwitterComposeViewController.m */, 150 | F8BC11E7119270670065FCB5 /* TwitterComposeViewController.xib */, 151 | F8BC11E8119270670065FCB5 /* TwitterAuthenticator.h */, 152 | F8BC11E9119270670065FCB5 /* TwitterAuthenticator.m */, 153 | F8BC11EA119270670065FCB5 /* TwitterConsumer.h */, 154 | F8BC11EB119270670065FCB5 /* TwitterConsumer.m */, 155 | F8BC11EC119270670065FCB5 /* TwitterLoginViewController.h */, 156 | F8BC11ED119270670065FCB5 /* TwitterLoginViewController.m */, 157 | F8BC11EE119270670065FCB5 /* TwitterLoginViewController.xib */, 158 | F8BC11EF119270670065FCB5 /* TwitterRequest.h */, 159 | F8BC11F0119270670065FCB5 /* TwitterRequest.m */, 160 | F8BC11F1119270670065FCB5 /* TwitterToken.h */, 161 | F8BC11F2119270670065FCB5 /* TwitterToken.m */, 162 | F8BC11F3119270670065FCB5 /* TwitterTweetPoster.h */, 163 | F8BC11F4119270670065FCB5 /* TwitterTweetPoster.m */, 164 | F8BC11F5119270670065FCB5 /* TwitterUtils.h */, 165 | F8BC11F6119270670065FCB5 /* TwitterUtils.m */, 166 | F8733C481193C50700680E83 /* TwitterClouds.png */, 167 | ); 168 | name = "Twitter Sources"; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | 1D6058900D05DD3D006BFB54 /* Test */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Test" */; 177 | buildPhases = ( 178 | 1D60588D0D05DD3D006BFB54 /* Resources */, 179 | 1D60588E0D05DD3D006BFB54 /* Sources */, 180 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | ); 186 | name = Test; 187 | productName = Test; 188 | productReference = 1D6058910D05DD3D006BFB54 /* Test.app */; 189 | productType = "com.apple.product-type.application"; 190 | }; 191 | /* End PBXNativeTarget section */ 192 | 193 | /* Begin PBXProject section */ 194 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 195 | isa = PBXProject; 196 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Test" */; 197 | compatibilityVersion = "Xcode 3.1"; 198 | developmentRegion = English; 199 | hasScannedForEncodings = 1; 200 | knownRegions = ( 201 | English, 202 | Japanese, 203 | French, 204 | German, 205 | ); 206 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 207 | projectDirPath = ""; 208 | projectRoot = ""; 209 | targets = ( 210 | 1D6058900D05DD3D006BFB54 /* Test */, 211 | ); 212 | }; 213 | /* End PBXProject section */ 214 | 215 | /* Begin PBXResourcesBuildPhase section */ 216 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 217 | isa = PBXResourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, 221 | 2899E5220DE3E06400AC0155 /* TestViewController.xib in Resources */, 222 | F8BC11F8119270670065FCB5 /* TwitterComposeViewController.xib in Resources */, 223 | F8BC11FC119270670065FCB5 /* TwitterLoginViewController.xib in Resources */, 224 | F8733C491193C50700680E83 /* TwitterClouds.png in Resources */, 225 | F83FEDFE11D7FC7200C6411C /* Twitter.strings in Resources */, 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | /* End PBXResourcesBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 237 | 1D3623260D0F684500981E51 /* TestAppDelegate.m in Sources */, 238 | 28D7ACF80DDB3853001CB0EB /* TestViewController.m in Sources */, 239 | F8BC11F7119270670065FCB5 /* TwitterComposeViewController.m in Sources */, 240 | F8BC11F9119270670065FCB5 /* TwitterAuthenticator.m in Sources */, 241 | F8BC11FA119270670065FCB5 /* TwitterConsumer.m in Sources */, 242 | F8BC11FB119270670065FCB5 /* TwitterLoginViewController.m in Sources */, 243 | F8BC11FD119270670065FCB5 /* TwitterRequest.m in Sources */, 244 | F8BC11FE119270670065FCB5 /* TwitterToken.m in Sources */, 245 | F8BC11FF119270670065FCB5 /* TwitterTweetPoster.m in Sources */, 246 | F8BC1200119270670065FCB5 /* TwitterUtils.m in Sources */, 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | /* End PBXSourcesBuildPhase section */ 251 | 252 | /* Begin PBXVariantGroup section */ 253 | F83FEDFC11D7FC7200C6411C /* Twitter.strings */ = { 254 | isa = PBXVariantGroup; 255 | children = ( 256 | F83FEDFD11D7FC7200C6411C /* English */, 257 | F83FEDFF11D7FC7C00C6411C /* French */, 258 | ); 259 | name = Twitter.strings; 260 | sourceTree = ""; 261 | }; 262 | /* End PBXVariantGroup section */ 263 | 264 | /* Begin XCBuildConfiguration section */ 265 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 266 | isa = XCBuildConfiguration; 267 | buildSettings = { 268 | ALWAYS_SEARCH_USER_PATHS = NO; 269 | COPY_PHASE_STRIP = NO; 270 | GCC_DYNAMIC_NO_PIC = NO; 271 | GCC_OPTIMIZATION_LEVEL = 0; 272 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 273 | GCC_PREFIX_HEADER = Test_Prefix.pch; 274 | INFOPLIST_FILE = "Test-Info.plist"; 275 | PRODUCT_NAME = Test; 276 | SDKROOT = iphoneos; 277 | }; 278 | name = Debug; 279 | }; 280 | 1D6058950D05DD3E006BFB54 /* Release */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | ALWAYS_SEARCH_USER_PATHS = NO; 284 | COPY_PHASE_STRIP = YES; 285 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 286 | GCC_PREFIX_HEADER = Test_Prefix.pch; 287 | INFOPLIST_FILE = "Test-Info.plist"; 288 | PRODUCT_NAME = Test; 289 | SDKROOT = iphoneos; 290 | VALIDATE_PRODUCT = YES; 291 | }; 292 | name = Release; 293 | }; 294 | C01FCF4F08A954540054247B /* Debug */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 298 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 299 | GCC_C_LANGUAGE_STANDARD = c99; 300 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 301 | GCC_WARN_UNUSED_VARIABLE = YES; 302 | PREBINDING = NO; 303 | SDKROOT = iphoneos3.1.3; 304 | }; 305 | name = Debug; 306 | }; 307 | C01FCF5008A954540054247B /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 311 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 312 | GCC_C_LANGUAGE_STANDARD = c99; 313 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 314 | GCC_WARN_UNUSED_VARIABLE = YES; 315 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 316 | PREBINDING = NO; 317 | SDKROOT = iphoneos3.1.3; 318 | }; 319 | name = Release; 320 | }; 321 | /* End XCBuildConfiguration section */ 322 | 323 | /* Begin XCConfigurationList section */ 324 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "Test" */ = { 325 | isa = XCConfigurationList; 326 | buildConfigurations = ( 327 | 1D6058940D05DD3E006BFB54 /* Debug */, 328 | 1D6058950D05DD3E006BFB54 /* Release */, 329 | ); 330 | defaultConfigurationIsVisible = 0; 331 | defaultConfigurationName = Release; 332 | }; 333 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Test" */ = { 334 | isa = XCConfigurationList; 335 | buildConfigurations = ( 336 | C01FCF4F08A954540054247B /* Debug */, 337 | C01FCF5008A954540054247B /* Release */, 338 | ); 339 | defaultConfigurationIsVisible = 0; 340 | defaultConfigurationName = Release; 341 | }; 342 | /* End XCConfigurationList section */ 343 | }; 344 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 345 | } 346 | -------------------------------------------------------------------------------- /Example/TestViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 800 5 | 10D573 6 | 762 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 87 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | 42 | 274 43 | 44 | YES 45 | 46 | 47 | 292 48 | {{79, 158}, {166, 37}} 49 | 50 | NO 51 | IBCocoaTouchFramework 52 | 0 53 | 0 54 | 55 | Helvetica-Bold 56 | 15 57 | 16 58 | 59 | 1 60 | Post to Twitter 61 | 62 | 3 63 | MQA 64 | 65 | 66 | 1 67 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 68 | 69 | 70 | 3 71 | MC41AA 72 | 73 | 74 | 75 | 76 | 292 77 | {{79, 231}, {166, 37}} 78 | 79 | NO 80 | IBCocoaTouchFramework 81 | 0 82 | 0 83 | 84 | 1 85 | Reset Stored Token 86 | 87 | 88 | 1 89 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 90 | 91 | 92 | 93 | 94 | {320, 460} 95 | 96 | 97 | 1 98 | MC45MDE5NjA3OTAyIDAuOTAxOTYwNzkwMiAwLjkwMTk2MDc5MDIAA 99 | 100 | NO 101 | 102 | IBCocoaTouchFramework 103 | 104 | 105 | 106 | 107 | YES 108 | 109 | 110 | view 111 | 112 | 113 | 114 | 7 115 | 116 | 117 | 118 | share 119 | 120 | 121 | 7 122 | 123 | 12 124 | 125 | 126 | 127 | reset 128 | 129 | 130 | 7 131 | 132 | 15 133 | 134 | 135 | 136 | 137 | YES 138 | 139 | 0 140 | 141 | 142 | 143 | 144 | 145 | -1 146 | 147 | 148 | File's Owner 149 | 150 | 151 | -2 152 | 153 | 154 | 155 | 156 | 6 157 | 158 | 159 | YES 160 | 161 | 162 | 163 | 164 | 165 | 166 | 8 167 | 168 | 169 | 170 | 171 | 13 172 | 173 | 174 | 175 | 176 | 177 | 178 | YES 179 | 180 | YES 181 | -1.CustomClassName 182 | -2.CustomClassName 183 | 13.IBPluginDependency 184 | 6.IBEditorWindowLastContentRect 185 | 6.IBPluginDependency 186 | 6.IBUserGuides 187 | 8.IBPluginDependency 188 | 189 | 190 | YES 191 | TestViewController 192 | UIResponder 193 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 194 | {{784, 527}, {320, 480}} 195 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 196 | 197 | YES 198 | 199 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 200 | 201 | 202 | 203 | YES 204 | 205 | 206 | YES 207 | 208 | 209 | 210 | 211 | YES 212 | 213 | 214 | YES 215 | 216 | 217 | 218 | 15 219 | 220 | 221 | 222 | YES 223 | 224 | TestViewController 225 | UIViewController 226 | 227 | YES 228 | 229 | YES 230 | reset 231 | share 232 | 233 | 234 | YES 235 | id 236 | id 237 | 238 | 239 | 240 | IBProjectSource 241 | Classes/TestViewController.h 242 | 243 | 244 | 245 | 246 | YES 247 | 248 | NSObject 249 | 250 | IBFrameworkSource 251 | Foundation.framework/Headers/NSError.h 252 | 253 | 254 | 255 | NSObject 256 | 257 | IBFrameworkSource 258 | Foundation.framework/Headers/NSFileManager.h 259 | 260 | 261 | 262 | NSObject 263 | 264 | IBFrameworkSource 265 | Foundation.framework/Headers/NSKeyValueCoding.h 266 | 267 | 268 | 269 | NSObject 270 | 271 | IBFrameworkSource 272 | Foundation.framework/Headers/NSKeyValueObserving.h 273 | 274 | 275 | 276 | NSObject 277 | 278 | IBFrameworkSource 279 | Foundation.framework/Headers/NSKeyedArchiver.h 280 | 281 | 282 | 283 | NSObject 284 | 285 | IBFrameworkSource 286 | Foundation.framework/Headers/NSNetServices.h 287 | 288 | 289 | 290 | NSObject 291 | 292 | IBFrameworkSource 293 | Foundation.framework/Headers/NSObject.h 294 | 295 | 296 | 297 | NSObject 298 | 299 | IBFrameworkSource 300 | Foundation.framework/Headers/NSPort.h 301 | 302 | 303 | 304 | NSObject 305 | 306 | IBFrameworkSource 307 | Foundation.framework/Headers/NSRunLoop.h 308 | 309 | 310 | 311 | NSObject 312 | 313 | IBFrameworkSource 314 | Foundation.framework/Headers/NSStream.h 315 | 316 | 317 | 318 | NSObject 319 | 320 | IBFrameworkSource 321 | Foundation.framework/Headers/NSThread.h 322 | 323 | 324 | 325 | NSObject 326 | 327 | IBFrameworkSource 328 | Foundation.framework/Headers/NSURL.h 329 | 330 | 331 | 332 | NSObject 333 | 334 | IBFrameworkSource 335 | Foundation.framework/Headers/NSURLConnection.h 336 | 337 | 338 | 339 | NSObject 340 | 341 | IBFrameworkSource 342 | Foundation.framework/Headers/NSXMLParser.h 343 | 344 | 345 | 346 | NSObject 347 | 348 | IBFrameworkSource 349 | UIKit.framework/Headers/UIAccessibility.h 350 | 351 | 352 | 353 | NSObject 354 | 355 | IBFrameworkSource 356 | UIKit.framework/Headers/UINibLoading.h 357 | 358 | 359 | 360 | NSObject 361 | 362 | IBFrameworkSource 363 | UIKit.framework/Headers/UIResponder.h 364 | 365 | 366 | 367 | UIButton 368 | UIControl 369 | 370 | IBFrameworkSource 371 | UIKit.framework/Headers/UIButton.h 372 | 373 | 374 | 375 | UIControl 376 | UIView 377 | 378 | IBFrameworkSource 379 | UIKit.framework/Headers/UIControl.h 380 | 381 | 382 | 383 | UIResponder 384 | NSObject 385 | 386 | 387 | 388 | UISearchBar 389 | UIView 390 | 391 | IBFrameworkSource 392 | UIKit.framework/Headers/UISearchBar.h 393 | 394 | 395 | 396 | UISearchDisplayController 397 | NSObject 398 | 399 | IBFrameworkSource 400 | UIKit.framework/Headers/UISearchDisplayController.h 401 | 402 | 403 | 404 | UIView 405 | 406 | IBFrameworkSource 407 | UIKit.framework/Headers/UITextField.h 408 | 409 | 410 | 411 | UIView 412 | UIResponder 413 | 414 | IBFrameworkSource 415 | UIKit.framework/Headers/UIView.h 416 | 417 | 418 | 419 | UIViewController 420 | 421 | IBFrameworkSource 422 | UIKit.framework/Headers/UINavigationController.h 423 | 424 | 425 | 426 | UIViewController 427 | 428 | IBFrameworkSource 429 | UIKit.framework/Headers/UITabBarController.h 430 | 431 | 432 | 433 | UIViewController 434 | UIResponder 435 | 436 | IBFrameworkSource 437 | UIKit.framework/Headers/UIViewController.h 438 | 439 | 440 | 441 | 442 | 0 443 | IBCocoaTouchFramework 444 | 445 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 446 | 447 | 448 | YES 449 | Test.xcodeproj 450 | 3 451 | 87 452 | 453 | 454 | -------------------------------------------------------------------------------- /Example/Test_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Test' target in the 'Test' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /Example/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Test 4 | // 5 | // Created by Stefan Arentz on 10-05-05. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | 13 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | [pool release]; 16 | return retVal; 17 | } 18 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1=. Objective-C / iPhone Twitter API 2 | 3 | p=. Version 0.1 -- Open Source (Apache License) 4 | 5 | p=. By "Stefan Arentz":mailto:stefan@arentz.ca, May 6th, 2010 6 | 7 | h2. Introduction 8 | 9 | This is a simple Objective-C API and GUI to access Twitter. The project includes ready-to-go interfaces for a login screen and a tweet composer. 10 | 11 | The library uses Twitter's XAuth authentication method. This is a new authentication method that does not need a web view to let the user login. Using XAuth you can ask the user for her username and password using a native GUI. 12 | 13 | The API is fully asynchronous and can be easily embedded in any project. There are no dependencies on other libraries. 14 | 15 | h2. Screenshots 16 | 17 | 18 | 19 | h2. Requirements 20 | 21 | The code has been developed and tested for iPhone OS 3.0 and higher. It does not use anything specific to 3.0 so it should also work on 2.2.1. 22 | 23 | To use this code you will need to sign up for Twitter API access and then open a support ticket with them to request XAuth access. 24 | 25 | h2. Example Usage 26 | 27 | A full working example is included in the project. The gist of it is here: 28 | 29 |

 30 | 
 31 | @interface TestViewController : UIViewController  {
 32 |   @private
 33 | 	TwitterConsumer* _consumer;
 34 | 	TwitterToken* _token;
 35 | }
 36 | 
 37 | - (IBAction) share;
 38 | 
 39 | @end
 40 | 
 41 | @implementation TestViewController
 42 | 
 43 | - (void) viewDidLoad
 44 | {
 45 | 	// Replace the key and secret with your own
 46 | 
 47 | 	_consumer = [[TwitterConsumer alloc] initWithKey: @"KEY" secret: @"SECRET"];
 48 |    
 49 | 	// Try to get the token from the keychain. If it does not exist then we will have to show the login dialog
 50 | 	// first. In a real application you should store the token in the user's keychain!
 51 | 	
 52 | 	NSData* tokenData = [[NSUserDefaults standardUserDefaults] dataForKey: @"Token"];
 53 | 	if (tokenData != nil)
 54 | 	{
 55 | 		_token = (TwitterToken*) [[NSKeyedUnarchiver unarchiveObjectWithData: tokenData] retain];
 56 | 	}
 57 | }
 58 | 
 59 | - (void) openTweetComposer
 60 | {
 61 | 	TweetComposeViewController* tweetComposeViewController = [[TweetComposeViewController new] autorelease];
 62 | 	if (tweetComposeViewController != nil)
 63 | 	{
 64 | 		tweetComposeViewController.consumer = _consumer;
 65 | 		tweetComposeViewController.token = _token;
 66 | 		tweetComposeViewController.message = @"I like Cheese";
 67 | 		tweetComposeViewController.delegate = self;
 68 | 
 69 | 		UINavigationController* navigationController = [[[UINavigationController alloc] initWithRootViewController: tweetComposeViewController] autorelease];
 70 | 		if (navigationController != nil) {
 71 | 			[self presentModalViewController: navigationController animated: YES];
 72 | 		}
 73 | 	}
 74 | }
 75 | 
 76 | - (IBAction) share
 77 | {
 78 | 	if (_token == nil)
 79 | 	{
 80 | 		TwitterLoginViewController* twitterLoginViewController = [[TwitterLoginViewController new] autorelease];
 81 | 		if (twitterLoginViewController != nil)
 82 | 		{
 83 | 			twitterLoginViewController.consumer = _consumer;
 84 | 			twitterLoginViewController.delegate = self;
 85 | 
 86 | 			UINavigationController* navigationController = [[[UINavigationController alloc] initWithRootViewController: twitterLoginViewController] autorelease];
 87 | 			if (navigationController != nil) {
 88 | 				[self presentModalViewController: navigationController animated: YES];
 89 | 			}
 90 | 		}
 91 | 	}
 92 | 	else
 93 | 	{
 94 | 		[self openTweetComposer];
 95 | 	}
 96 | }
 97 | 
 98 | #pragma mark -
 99 | 
100 | - (void) twitterLoginViewControllerDidCancel: (TwitterLoginViewController*) twitterLoginViewController
101 | {
102 | 	[twitterLoginViewController dismissModalViewControllerAnimated: YES];
103 | }
104 | 
105 | - (void) twitterLoginViewController: (TwitterLoginViewController*) twitterLoginViewController didSucceedWithToken: (TwitterToken*) token
106 | {
107 | 	_token = [token retain];
108 | 
109 | 	// Save the token to the user defaults
110 | 
111 | 	[[NSUserDefaults standardUserDefaults] setObject: [NSKeyedArchiver archivedDataWithRootObject: _token] forKey: @"Token"];
112 | 	[[NSUserDefaults standardUserDefaults] synchronize];
113 | 	
114 | 	// Open the tweet composer and dismiss the login screen
115 | 
116 | 	TweetComposeViewController* tweetComposeViewController = [[TweetComposeViewController new] autorelease];
117 | 	if (tweetComposeViewController != nil)
118 | 	{
119 | 		tweetComposeViewController.consumer = _consumer;
120 | 		tweetComposeViewController.token = _token;
121 | 		tweetComposeViewController.message = @"I like Cheese";
122 | 		tweetComposeViewController.delegate = self;
123 | 		
124 | 		[twitterLoginViewController.navigationController pushViewController: tweetComposeViewController animated: YES];
125 | 	}
126 | }
127 | 
128 | - (void) twitterLoginViewController: (TwitterLoginViewController*) twitterLoginViewController didFailWithError: (NSError*) error
129 | {
130 | 	NSLog(@"twitterLoginViewController: %@ didFailWithError: %@", self, error);
131 | }
132 | 
133 | #pragma mark -
134 | 
135 | - (void) tweetComposeViewControllerDidCancel: (TweetComposeViewController*) tweetComposeViewController
136 | {
137 | 	[tweetComposeViewController dismissModalViewControllerAnimated: YES];
138 | }
139 | 
140 | - (void) tweetComposeViewControllerDidSucceed: (TweetComposeViewController*) tweetComposeViewController
141 | {
142 | 	[tweetComposeViewController dismissModalViewControllerAnimated: YES];
143 | }
144 | 
145 | - (void) tweetComposeViewController: (TweetComposeViewController*) tweetComposeViewController didFailWithError: (NSError*) error
146 | {
147 | 	[tweetComposeViewController dismissModalViewControllerAnimated: YES];
148 | }
149 | 
150 | #pragma mark -
151 | 
152 | - (void) dealloc
153 | {
154 | 	[_consumer release];
155 | 	[_token release];
156 | 	[super dealloc];
157 | }
158 | 
159 | @end
160 | 
161 | 162 | -------------------------------------------------------------------------------- /Sources/English.lproj/Twitter.strings: -------------------------------------------------------------------------------- 1 | /* Twitter.strings - English */ 2 | 3 | "Cancel" = "Cancel"; 4 | "OK" = "OK"; 5 | "Login" = "Login"; 6 | "CreateATwitterAccount" = "Create a Twitter Account"; 7 | "UpdatingStatus" = "Updating status ..."; 8 | "SigningIn" = "Signing in ..."; 9 | "Send" = "Send"; 10 | "NewMessage" = "New Message"; 11 | "Username" = "Username"; 12 | "Password" = "Password"; 13 | "Required" = "Required"; 14 | "ShorteningLinks" = "Shortening linls ..."; 15 | -------------------------------------------------------------------------------- /Sources/French.lproj/Twitter.strings: -------------------------------------------------------------------------------- 1 | /* Twitter.strings - French */ 2 | 3 | "Cancel" = "Annuler"; 4 | "OK" = "OK"; 5 | "Login" = "Connexion"; 6 | "CreateATwitterAccount" = "Create a Twitter Account"; 7 | "UpdatingStatus" = "Mise à jour de votre statut ..."; 8 | "SigningIn" = "Ouverture de session ..."; 9 | "Send" = "Envoyer"; 10 | "NewMessage" = "Nouv. message"; 11 | "Username" = "Nom d'utilisateur"; 12 | "Password" = "Mot de passe"; 13 | "Required" = "Requi"; 14 | "ShorteningLinks" = "Shortening linls ..."; 15 | -------------------------------------------------------------------------------- /Sources/TwitterAuthenticator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | #import "TwitterRequest.h" 23 | 24 | @class TwitterConsumer; 25 | @class TwitterToken; 26 | @class TwitterAuthenticator; 27 | @class TwitterRequest; 28 | 29 | @protocol TwitterAuthenticatorDelegate 30 | - (void) twitterAuthenticator: (TwitterAuthenticator*) twitterAuthenticator didFailWithError: (NSError*) error; 31 | - (void) twitterAuthenticator: (TwitterAuthenticator*) twitterAuthenticator didSucceedWithToken: (TwitterToken*) token; 32 | @end 33 | 34 | @interface TwitterAuthenticator : NSObject { 35 | @private 36 | TwitterConsumer* _consumer; 37 | NSString* _username; 38 | NSString* _password; 39 | id _delegate; 40 | @private 41 | TwitterRequest* _twitterRequest; 42 | } 43 | 44 | @property (nonatomic,retain) TwitterConsumer* consumer; 45 | 46 | @property (nonatomic,retain) NSString* username; 47 | @property (nonatomic,retain) NSString* password; 48 | 49 | @property (nonatomic,assign) id delegate; 50 | 51 | - (void) authenticate; 52 | - (void) cancel; 53 | 54 | @end -------------------------------------------------------------------------------- /Sources/TwitterAuthenticator.m: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import "TwitterConsumer.h" 21 | #import "TwitterToken.h" 22 | #import "TwitterRequest.h" 23 | #import "TwitterAuthenticator.h" 24 | 25 | @implementation TwitterAuthenticator 26 | 27 | #pragma mark - 28 | 29 | @synthesize 30 | consumer = _consumer, 31 | username = _username, 32 | password = _password, 33 | delegate = _delegate; 34 | 35 | #pragma mark - 36 | 37 | - (id) init 38 | { 39 | if ((self = [super init]) != nil) { 40 | } 41 | return self; 42 | } 43 | 44 | - (void) dealloc 45 | { 46 | [_twitterRequest release]; 47 | [_consumer release]; 48 | [_username release]; 49 | [_password release]; 50 | [super dealloc]; 51 | } 52 | 53 | #pragma mark - 54 | 55 | - (NSString*) _formEncodeString: (NSString*) string 56 | { 57 | NSString* encoded = (NSString*) CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef) string, NULL, CFSTR("!*'();:@&=+$,/?%#[]"), kCFStringEncodingUTF8); 58 | return [encoded autorelease]; 59 | } 60 | 61 | - (NSString*) _formDecodeString: (NSString*) string 62 | { 63 | NSString* decoded = (NSString*) CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault, (CFStringRef) string, NULL); 64 | return [decoded autorelease]; 65 | } 66 | 67 | #pragma mark - 68 | 69 | - (void) authenticate 70 | { 71 | if (_twitterRequest == nil) 72 | { 73 | NSDictionary* parameters = [NSDictionary dictionaryWithObjectsAndKeys: 74 | _username, @"x_auth_username", 75 | _password, @"x_auth_password", 76 | @"client_auth", @"x_auth_mode", 77 | nil]; 78 | 79 | _twitterRequest = [TwitterRequest new]; 80 | 81 | _twitterRequest.url = [NSURL URLWithString: @"https://api.twitter.com/oauth/access_token"]; 82 | _twitterRequest.twitterConsumer = _consumer; 83 | _twitterRequest.method = @"POST"; 84 | _twitterRequest.parameters = parameters; 85 | _twitterRequest.delegate = self; 86 | 87 | [_twitterRequest execute]; 88 | } 89 | } 90 | 91 | - (void) cancel 92 | { 93 | if (_twitterRequest != nil) { 94 | [_twitterRequest release]; 95 | _twitterRequest = nil; 96 | } 97 | } 98 | 99 | #pragma mark - 100 | 101 | - (void) twitterRequest: (TwitterRequest*) request didFailWithError: (NSError*) error 102 | { 103 | [_delegate twitterAuthenticator: self didFailWithError: error]; 104 | 105 | [_twitterRequest release]; 106 | _twitterRequest = nil; 107 | } 108 | 109 | - (void) twitterRequest:(TwitterRequest *)request didFinishLoadingData: (NSData*) data 110 | { 111 | // Get the response data as a string 112 | 113 | NSString* response = [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease]; 114 | if (response == nil) { 115 | response = [[[NSString alloc] initWithData: data encoding: NSASCIIStringEncoding] autorelease]; 116 | } 117 | 118 | if (response == nil) { 119 | // TODO: Real error handling 120 | [_delegate twitterAuthenticator: self didFailWithError: nil]; 121 | return; 122 | } 123 | 124 | // Parse the response into name/value pairs into a dictionary 125 | 126 | NSMutableDictionary* parameters = [NSMutableDictionary dictionary]; 127 | 128 | NSArray* pairs = [response componentsSeparatedByString: @"&"]; 129 | for (NSString* pair in pairs) 130 | { 131 | NSArray* nameValue = [pair componentsSeparatedByString: @"="]; 132 | if ([nameValue count] == 2) 133 | { 134 | [parameters setValue: [self _formDecodeString: [nameValue objectAtIndex: 1]] forKey: [nameValue objectAtIndex: 0]]; 135 | } 136 | } 137 | 138 | // Call the delegate with the token or with an error if we could not parse the token values 139 | 140 | NSString* tokenValue = [parameters valueForKey: @"oauth_token"]; 141 | NSString* tokenSecret = [parameters valueForKey: @"oauth_token_secret"]; 142 | 143 | if (tokenValue != nil && tokenSecret != nil) { 144 | TwitterToken* token = [[[TwitterToken alloc] initWithToken: tokenValue secret: tokenSecret] autorelease]; 145 | [_delegate twitterAuthenticator: self didSucceedWithToken: token]; 146 | } else { 147 | // TODO: Real error handling 148 | [_delegate twitterAuthenticator: self didFailWithError: nil]; 149 | } 150 | 151 | // Release all our resources 152 | 153 | [_twitterRequest release]; 154 | _twitterRequest = nil; 155 | } 156 | 157 | @end -------------------------------------------------------------------------------- /Sources/TwitterClouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/st3fan/iphone-twitter/fe4b11ffd384df4503f60e0878a138edee3ea595/Sources/TwitterClouds.png -------------------------------------------------------------------------------- /Sources/TwitterComposeViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | #import "TwitterTweetPoster.h" 23 | 24 | #if defined(TWITTER_USE_URLSHORTENER) 25 | #import "URLShortenerCredentials.h" 26 | #import "URLShortener.h" 27 | #endif 28 | 29 | @class TwitterToken; 30 | @class TwitterConsumer; 31 | @class TwitterComposeViewController; 32 | 33 | @protocol TwitterComposeViewControllerDelegate 34 | - (void) twitterComposeViewControllerDidCancel: (TwitterComposeViewController*) twitterComposeViewController; 35 | - (void) twitterComposeViewControllerDidSucceed: (TwitterComposeViewController*) twitterComposeViewController; 36 | - (void) twitterComposeViewController: (TwitterComposeViewController*) twitterComposeViewController didFailWithError: (NSError*) error; 37 | @end 38 | 39 | @interface TwitterComposeViewController : UIViewController { 40 | @private 41 | IBOutlet UIView* _containerView; 42 | IBOutlet UITextView* _textView; 43 | IBOutlet UILabel* _charactersLeftLabel; 44 | IBOutlet UILabel* _statusLabel; 45 | IBOutlet UIActivityIndicatorView* _activityIndicatorView; 46 | @private 47 | id _delegate; 48 | TwitterConsumer* _consumer; 49 | TwitterToken* _token; 50 | NSString* _message; 51 | @private 52 | #if defined(TWITTER_USE_URLSHORTENER) 53 | BOOL _linkShortenerEnabled; 54 | URLShortenerCredentials* _linkShortenerCredentials; 55 | #endif 56 | @private 57 | TwitterTweetPoster* _tweetPoster; 58 | } 59 | 60 | @property (nonatomic,assign) id delegate; 61 | @property (nonatomic,retain) TwitterToken* token; 62 | @property (nonatomic,retain) TwitterConsumer* consumer; 63 | @property (nonatomic,retain) NSString* message; 64 | 65 | #if defined(TWITTER_USE_URLSHORTENER) 66 | @property (nonatomic,assign) BOOL linkShortenerEnabled; 67 | @property (nonatomic,retain) URLShortenerCredentials* linkShortenerCredentials; 68 | #endif 69 | 70 | - (IBAction) close; 71 | - (IBAction) send; 72 | 73 | @end -------------------------------------------------------------------------------- /Sources/TwitterComposeViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | #import "TwitterConsumer.h" 23 | #import "TwitterToken.h" 24 | #import "TwitterTweetPoster.h" 25 | #import "TwitterComposeViewController.h" 26 | 27 | #if defined(TWITTER_USE_URLSHORTENER) 28 | #import "RegexKitLite.h" 29 | #endif 30 | 31 | @implementation TwitterComposeViewController 32 | 33 | @synthesize delegate = _delegate, token = _token, message = _message, consumer = _consumer; 34 | 35 | #if defined(TWITTER_USE_URLSHORTENER) 36 | @synthesize linkShortenerEnabled = _linkShortenerEnabled, linkShortenerCredentials = _linkShortenerCredentials; 37 | #endif 38 | 39 | #pragma mark - 40 | 41 | - (void) _hideComposeForm 42 | { 43 | _textView.hidden = YES; 44 | [_textView resignFirstResponder]; 45 | 46 | _charactersLeftLabel.hidden = YES; 47 | } 48 | 49 | - (void) _showComposeForm 50 | { 51 | _textView.hidden = NO; 52 | [_textView becomeFirstResponder]; 53 | 54 | _charactersLeftLabel.hidden = NO; 55 | } 56 | 57 | - (void) _hideStatus 58 | { 59 | _activityIndicatorView.hidden = YES; 60 | [_activityIndicatorView stopAnimating]; 61 | _statusLabel.hidden = YES; 62 | } 63 | 64 | - (void) _showStatus: (NSString*) status 65 | { 66 | _statusLabel.text = status; 67 | 68 | _activityIndicatorView.hidden = NO; 69 | [_activityIndicatorView startAnimating]; 70 | _statusLabel.hidden = NO; 71 | } 72 | 73 | #if defined(TWITTER_USE_URLSHORTENER) 74 | 75 | #pragma mark - 76 | 77 | - (void) shortener: (URLShortener*) shortener didSucceedWithShortenedURL: (NSURL*) shortenedURL 78 | { 79 | // Replace the first URL in the message. This is terrible code that needs to be replaced with a proper regular expression. 80 | 81 | NSMutableString* message = [NSMutableString string]; 82 | 83 | for (NSString* word in [_message componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]) { 84 | if ([word hasPrefix: @"http://"] || [word hasPrefix: @"https://"]) { 85 | [message appendString: @" "]; 86 | [message appendString: [shortenedURL absoluteString]]; 87 | } else { 88 | [message appendString: @" "]; 89 | [message appendString: word]; 90 | } 91 | } 92 | 93 | _textView.text = message; 94 | [self updateCharactersLeftLabel]; 95 | 96 | [self _showComposeForm]; 97 | [self _hideStatus]; 98 | } 99 | 100 | - (void) shortener: (URLShortener*) shortener didFailWithStatusCode: (int) statusCode 101 | { 102 | [self _showComposeForm]; 103 | [self _hideStatus]; 104 | } 105 | 106 | - (void) shortener: (URLShortener*) shortener didFailWithError: (NSError*) error 107 | { 108 | [self _showComposeForm]; 109 | [self _hideStatus]; 110 | } 111 | 112 | - (void) _shortenLinks 113 | { 114 | NSURL* url = nil; 115 | 116 | for (NSString* word in [_message componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]) { 117 | if ([word hasPrefix: @"http://"] || [word hasPrefix: @"https://"]) { 118 | url = [NSURL URLWithString: word]; 119 | break; 120 | } 121 | } 122 | 123 | if (url != nil) 124 | { 125 | NSLog(@"Shortening link %@", [url absoluteString]); 126 | 127 | URLShortener* shortener = [[URLShortener new] autorelease]; 128 | if (shortener != nil) 129 | { 130 | shortener.delegate = self; 131 | shortener.url = url; 132 | shortener.credentials = _linkShortenerCredentials; 133 | [shortener execute]; 134 | } 135 | } 136 | } 137 | 138 | - (BOOL) _messageContainsLinks 139 | { 140 | BOOL messageContainsLinks = NO; 141 | 142 | if (_message && [_message length] != 0) 143 | { 144 | for (NSString* word in [_message componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]) { 145 | if ([word hasPrefix: @"http://"] || [word hasPrefix: @"https://"]) { 146 | messageContainsLinks = YES; 147 | break; 148 | } 149 | } 150 | } 151 | 152 | return messageContainsLinks; 153 | } 154 | 155 | #endif 156 | 157 | #pragma mark - 158 | 159 | - (IBAction) close 160 | { 161 | @try { 162 | [_delegate twitterComposeViewControllerDidCancel: self]; 163 | } @catch (NSException* exception) { 164 | NSLog(@"TwitterComposeViewController caught an unexpected exception while calling the delegate: %@", exception); 165 | } 166 | } 167 | 168 | - (IBAction) send 169 | { 170 | if ([_textView.text length] > 140) 171 | { 172 | UIAlertView* alertView = [[UIAlertView alloc] initWithTitle: @"The tweet is too long" message: @"Twitter messages can only be up to 140 characters long." delegate: nil 173 | cancelButtonTitle: NSLocalizedStringFromTable(@"OK", @"Twitter", @"") otherButtonTitles: nil]; 174 | if (alertView != nil) { 175 | [alertView show]; 176 | [alertView release]; 177 | } 178 | } 179 | else 180 | { 181 | [self _hideComposeForm]; 182 | [self _showStatus: NSLocalizedStringFromTable(@"UpdatingStatus", @"Twitter", @"")]; 183 | 184 | _tweetPoster = [TwitterTweetPoster new]; 185 | if (_tweetPoster != nil) { 186 | _tweetPoster.consumer = _consumer; 187 | _tweetPoster.token = _token; 188 | _tweetPoster.delegate = self; 189 | _tweetPoster.message = _textView.text; 190 | [_tweetPoster execute]; 191 | } 192 | } 193 | } 194 | 195 | #pragma mark - 196 | 197 | - (void) updateCharactersLeftLabel 198 | { 199 | NSInteger count = 140 - [_textView.text length]; 200 | 201 | if (count < 0) { 202 | _charactersLeftLabel.textColor = [UIColor redColor]; 203 | } else { 204 | _charactersLeftLabel.textColor = [UIColor grayColor]; 205 | } 206 | 207 | _charactersLeftLabel.text = [NSString stringWithFormat: @"%d", count]; 208 | } 209 | 210 | #pragma mark - 211 | 212 | - (void) viewDidLoad 213 | { 214 | _containerView.layer.cornerRadius = 10; 215 | 216 | _textView.text = _message; 217 | _textView.delegate = self; 218 | 219 | [self updateCharactersLeftLabel]; 220 | 221 | self.title = NSLocalizedStringFromTable(@"NewMessage", @"Twitter", @""); 222 | 223 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: NSLocalizedStringFromTable(@"Cancel", @"Twitter", @"") 224 | style: UIBarButtonItemStylePlain target: self action: @selector(close)]; 225 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: NSLocalizedStringFromTable(@"Send", @"Twitter", @"") 226 | style: UIBarButtonItemStyleDone target: self action: @selector(send)]; 227 | } 228 | 229 | - (void) viewWillAppear: (BOOL) animated 230 | { 231 | #if defined(TWITTER_USE_URLSHORTENER) 232 | if (_linkShortenerEnabled == YES && [self _messageContainsLinks]) { 233 | [self _hideComposeForm]; 234 | [self _showStatus: NSLocalizedStringFromTable(@"ShorteningLinks", @"Twitter", @"")]; 235 | [self _shortenLinks]; 236 | } else { 237 | [self _showComposeForm]; 238 | [self _hideStatus]; 239 | } 240 | #else 241 | [self _showComposeForm]; 242 | [self _hideStatus]; 243 | #endif 244 | } 245 | 246 | #pragma mark - 247 | 248 | - (void) textViewDidChange: (UITextView*) textView 249 | { 250 | [self updateCharactersLeftLabel]; 251 | } 252 | 253 | #pragma mark - 254 | 255 | - (void) twitterTweetPosterDidSucceed: (TwitterTweetPoster*) twitterTweetPoster 256 | { 257 | [_delegate twitterComposeViewControllerDidSucceed: self]; 258 | } 259 | 260 | - (void) twitterTweetPoster: (TwitterTweetPoster*) twitterTweetPoster didFailWithError: (NSError*) error 261 | { 262 | [_delegate twitterComposeViewController: self didFailWithError: error]; 263 | } 264 | 265 | #pragma mark - 266 | 267 | - (void) dealloc 268 | { 269 | [_tweetPoster release]; 270 | [super dealloc]; 271 | } 272 | 273 | @end -------------------------------------------------------------------------------- /Sources/TwitterComposeViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10F569 6 | 788 7 | 1038.29 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 117 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | 42 | 274 43 | 44 | YES 45 | 46 | 47 | 256 48 | {320, 416} 49 | 50 | NO 51 | YES 52 | 4 53 | YES 54 | IBCocoaTouchFramework 55 | 56 | NSImage 57 | TwitterClouds.png 58 | 59 | 60 | 61 | 62 | 292 63 | 64 | YES 65 | 66 | 67 | 282 68 | {{5, 5}, {272, 145}} 69 | 70 | 71 | 1 72 | MSAxIDEAA 73 | 74 | YES 75 | YES 76 | IBCocoaTouchFramework 77 | NO 78 | NO 79 | NO 80 | NO 81 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. 82 | 83 | Helvetica 84 | 19 85 | 16 86 | 87 | 88 | 2 89 | IBCocoaTouchFramework 90 | 91 | 92 | 93 | 94 | 292 95 | {{20, 62}, {248, 26}} 96 | 97 | NO 98 | YES 99 | 7 100 | NO 101 | IBCocoaTouchFramework 102 | #UpdatingStatus# 103 | 104 | Helvetica-Bold 105 | 19 106 | 16 107 | 108 | 109 | 1 110 | MCAwIDAAA 111 | 112 | 113 | 1 114 | 10 115 | 1 116 | 117 | 118 | 119 | 292 120 | {{131, 96}, {20, 20}} 121 | 122 | NO 123 | IBCocoaTouchFramework 124 | NO 125 | 2 126 | 127 | 128 | 129 | 269 130 | {{239, 150}, {42, 21}} 131 | 132 | 133 | NO 134 | YES 135 | 7 136 | NO 137 | IBCocoaTouchFramework 138 | 123 139 | 140 | Helvetica 141 | 13 142 | 16 143 | 144 | 145 | 1 146 | MC42MDAwMDAwMjM4IDAuNjAwMDAwMDIzOCAwLjYwMDAwMDAyMzgAA 147 | 148 | 149 | 1 150 | 10 151 | 2 152 | 153 | 154 | {{17, 15}, {288, 177}} 155 | 156 | 157 | 3 158 | MQA 159 | 160 | 2 161 | 162 | 163 | IBCocoaTouchFramework 164 | 165 | 166 | {320, 416} 167 | 168 | 169 | 3 170 | MQA 171 | 172 | 173 | 174 | 175 | NO 176 | 177 | IBCocoaTouchFramework 178 | 179 | 180 | 181 | 182 | YES 183 | 184 | 185 | view 186 | 187 | 188 | 189 | 3 190 | 191 | 192 | 193 | _charactersLeftLabel 194 | 195 | 196 | 197 | 17 198 | 199 | 200 | 201 | _textView 202 | 203 | 204 | 205 | 18 206 | 207 | 208 | 209 | _containerView 210 | 211 | 212 | 213 | 23 214 | 215 | 216 | 217 | _statusLabel 218 | 219 | 220 | 221 | 26 222 | 223 | 224 | 225 | _activityIndicatorView 226 | 227 | 228 | 229 | 27 230 | 231 | 232 | 233 | 234 | YES 235 | 236 | 0 237 | 238 | 239 | 240 | 241 | 242 | 1 243 | 244 | 245 | YES 246 | 247 | 248 | 249 | 250 | 251 | 252 | -1 253 | 254 | 255 | File's Owner 256 | 257 | 258 | -2 259 | 260 | 261 | 262 | 263 | 21 264 | 265 | 266 | 267 | 268 | 22 269 | 270 | 271 | YES 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 4 281 | 282 | 283 | 284 | 285 | 14 286 | 287 | 288 | 289 | 290 | 24 291 | 292 | 293 | 294 | 295 | 25 296 | 297 | 298 | 299 | 300 | 301 | 302 | YES 303 | 304 | YES 305 | -1.CustomClassName 306 | -2.CustomClassName 307 | 1.IBEditorWindowLastContentRect 308 | 1.IBPluginDependency 309 | 14.IBPluginDependency 310 | 22.IBPluginDependency 311 | 24.IBPluginDependency 312 | 25.IBPluginDependency 313 | 4.IBPluginDependency 314 | 315 | 316 | YES 317 | TwitterComposeViewController 318 | UIResponder 319 | {{983, 462}, {320, 480}} 320 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 321 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 322 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 323 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 324 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 325 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 326 | 327 | 328 | 329 | YES 330 | 331 | 332 | YES 333 | 334 | 335 | 336 | 337 | YES 338 | 339 | 340 | YES 341 | 342 | 343 | 344 | 27 345 | 346 | 347 | 348 | YES 349 | 350 | NSObject 351 | 352 | IBProjectSource 353 | ThirdPartySources/json-framework-2.2.3/Source/NSObject+SBJSON.h 354 | 355 | 356 | 357 | NSObject 358 | 359 | IBProjectSource 360 | ThirdPartySources/json-framework-2.2.3/Source/SBJsonWriter.h 361 | 362 | 363 | 364 | TwitterComposeViewController 365 | UIViewController 366 | 367 | YES 368 | 369 | YES 370 | close 371 | send 372 | 373 | 374 | YES 375 | id 376 | id 377 | 378 | 379 | 380 | YES 381 | 382 | YES 383 | close 384 | send 385 | 386 | 387 | YES 388 | 389 | close 390 | id 391 | 392 | 393 | send 394 | id 395 | 396 | 397 | 398 | 399 | YES 400 | 401 | YES 402 | _activityIndicatorView 403 | _charactersLeftLabel 404 | _containerView 405 | _statusLabel 406 | _textView 407 | 408 | 409 | YES 410 | UIActivityIndicatorView 411 | UILabel 412 | UIView 413 | UILabel 414 | UITextView 415 | 416 | 417 | 418 | YES 419 | 420 | YES 421 | _activityIndicatorView 422 | _charactersLeftLabel 423 | _containerView 424 | _statusLabel 425 | _textView 426 | 427 | 428 | YES 429 | 430 | _activityIndicatorView 431 | UIActivityIndicatorView 432 | 433 | 434 | _charactersLeftLabel 435 | UILabel 436 | 437 | 438 | _containerView 439 | UIView 440 | 441 | 442 | _statusLabel 443 | UILabel 444 | 445 | 446 | _textView 447 | UITextView 448 | 449 | 450 | 451 | 452 | IBProjectSource 453 | ThirdPartySources/iphone-twitter/Sources/TwitterComposeViewController.h 454 | 455 | 456 | 457 | 458 | 0 459 | IBCocoaTouchFramework 460 | 461 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 462 | 463 | 464 | 465 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 466 | 467 | 468 | YES 469 | ../../../DavidSuzuki.xcodeproj 470 | 3 471 | 472 | TwitterClouds.png 473 | {320, 416} 474 | 475 | 117 476 | 477 | 478 | -------------------------------------------------------------------------------- /Sources/TwitterConsumer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | @interface TwitterConsumer : NSObject { 23 | @private 24 | NSString* _key; 25 | NSString* _secret; 26 | } 27 | 28 | @property (nonatomic,readonly) NSString* key; 29 | @property (nonatomic,readonly) NSString* secret; 30 | 31 | - (id) initWithKey: (NSString*) key secret: (NSString*) secret; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Sources/TwitterConsumer.m: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import "TwitterConsumer.h" 21 | 22 | @implementation TwitterConsumer 23 | 24 | @synthesize 25 | key = _key, 26 | secret = _secret; 27 | 28 | - (id) initWithKey: (NSString*) key secret: (NSString*) secret 29 | { 30 | if ((self = [super init]) != nil) { 31 | _key = [key retain]; 32 | _secret = [secret retain]; 33 | } 34 | return self; 35 | } 36 | 37 | - (void) dealloc 38 | { 39 | [_key release]; 40 | [_secret release]; 41 | [super dealloc]; 42 | } 43 | 44 | @end -------------------------------------------------------------------------------- /Sources/TwitterLoginViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | #import "TwitterAuthenticator.h" 23 | 24 | @class TwitterConsumer; 25 | @class TwitterToken; 26 | @class TwitterLoginViewController; 27 | 28 | @protocol TwitterLoginViewControllerDelegate 29 | - (void) twitterLoginViewControllerDidCancel: (TwitterLoginViewController*) twitterLoginViewController; 30 | - (void) twitterLoginViewController: (TwitterLoginViewController*) twitterLoginViewController didSucceedWithToken: (TwitterToken*) token; 31 | - (void) twitterLoginViewController: (TwitterLoginViewController*) twitterLoginViewController didFailWithError: (NSError*) error; 32 | @end 33 | 34 | @interface TwitterLoginViewController : UIViewController { 35 | @private 36 | TwitterConsumer* _consumer; 37 | id _delegate; 38 | @private 39 | UIBarButtonItem* _loginButton; 40 | IBOutlet UIView* _containerView; 41 | IBOutlet UITextField* _usernameTextField; 42 | IBOutlet UILabel* _usernameLabel; 43 | IBOutlet UITextField* _passwordTextField; 44 | IBOutlet UILabel* _passwordLabel; 45 | IBOutlet UILabel* _statusLabel; 46 | IBOutlet UIActivityIndicatorView* _activityIndicatorView; 47 | IBOutlet UIButton* _createAccountButton; 48 | @private 49 | TwitterAuthenticator* _authenticator; 50 | } 51 | 52 | - (IBAction) cancel; 53 | - (IBAction) login; 54 | - (IBAction) createAccount; 55 | 56 | @property (nonatomic,retain) TwitterConsumer* consumer; 57 | @property (nonatomic,assign) id delegate; 58 | 59 | @end -------------------------------------------------------------------------------- /Sources/TwitterLoginViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | #import "TwitterAuthenticator.h" 23 | #import "TwitterLoginViewController.h" 24 | 25 | @implementation TwitterLoginViewController 26 | 27 | @synthesize consumer = _consumer, delegate = _delegate; 28 | 29 | - (void) _hideLoginForm 30 | { 31 | _usernameLabel.hidden = YES; 32 | _usernameTextField.hidden = YES; 33 | _passwordLabel.hidden = YES; 34 | _passwordTextField.hidden = YES; 35 | _createAccountButton.hidden = YES; 36 | 37 | [_usernameTextField resignFirstResponder]; 38 | [_passwordTextField resignFirstResponder]; 39 | } 40 | 41 | - (void) _showLoginForm 42 | { 43 | _usernameLabel.hidden = NO; 44 | _usernameTextField.hidden = NO; 45 | _passwordLabel.hidden = NO; 46 | _passwordTextField.hidden = NO; 47 | _createAccountButton.hidden = NO; 48 | } 49 | 50 | - (void) _hideStatus 51 | { 52 | _activityIndicatorView.hidden = YES; 53 | [_activityIndicatorView stopAnimating]; 54 | _statusLabel.hidden = YES; 55 | } 56 | 57 | - (void) _showStatus 58 | { 59 | _activityIndicatorView.hidden = NO; 60 | [_activityIndicatorView startAnimating]; 61 | _statusLabel.hidden = NO; 62 | } 63 | 64 | #pragma mark - 65 | 66 | - (void) viewDidLoad 67 | { 68 | [self _hideStatus]; 69 | 70 | _loginButton.enabled = NO; 71 | 72 | _containerView.layer.cornerRadius = 15; 73 | 74 | self.title = NSLocalizedStringFromTable(@"Login", @"Twitter", @""); 75 | 76 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: NSLocalizedStringFromTable(@"Cancel", @"Twitter", @"") 77 | style: UIBarButtonItemStylePlain target: self action: @selector(cancel)]; 78 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: NSLocalizedStringFromTable(@"Login", @"Twitter", @"") 79 | style: UIBarButtonItemStyleDone target: self action: @selector(login)]; 80 | self.navigationItem.rightBarButtonItem.enabled = NO; 81 | 82 | [_usernameTextField addTarget: self action: @selector(updateLoginButton) forControlEvents: UIControlEventEditingChanged]; 83 | _usernameTextField.placeholder = NSLocalizedStringFromTable(@"Required", @"Twitter", @""); 84 | 85 | [_passwordTextField addTarget: self action: @selector(updateLoginButton) forControlEvents: UIControlEventEditingChanged]; 86 | _passwordTextField.placeholder = NSLocalizedStringFromTable(@"Required", @"Twitter", @""); 87 | 88 | [_createAccountButton setTitle: NSLocalizedStringFromTable(@"CreateATwitterAccount", @"Twitter", @"") forState: UIControlStateNormal]; 89 | _usernameLabel.text = NSLocalizedStringFromTable(@"Username", @"Twitter", @""); 90 | _passwordLabel.text = NSLocalizedStringFromTable(@"Password", @"Twitter", @""); 91 | _statusLabel.text = NSLocalizedStringFromTable(@"SigningIn", @"Twitter", @""); 92 | } 93 | 94 | #pragma mark - 95 | 96 | - (IBAction) cancel 97 | { 98 | [_delegate twitterLoginViewControllerDidCancel: self]; 99 | } 100 | 101 | - (IBAction) login 102 | { 103 | [self _hideLoginForm]; 104 | [self _showStatus]; 105 | 106 | self.navigationItem.rightBarButtonItem.enabled = NO; 107 | 108 | if (_authenticator == nil) { 109 | _authenticator = [TwitterAuthenticator new]; 110 | } 111 | 112 | _authenticator.consumer = _consumer; 113 | _authenticator.username = _usernameTextField.text; 114 | _authenticator.password = _passwordTextField.text; 115 | _authenticator.delegate = self; 116 | 117 | [_authenticator authenticate]; 118 | } 119 | 120 | - (IBAction) createAccount 121 | { 122 | } 123 | 124 | #pragma mark - 125 | 126 | - (BOOL) textFieldShouldReturn: (UITextField*) textField 127 | { 128 | if (textField == _usernameTextField) { 129 | [_passwordTextField becomeFirstResponder]; 130 | } 131 | 132 | if (textField == _passwordTextField) { 133 | NSLog(@"Logging in"); 134 | } 135 | 136 | return YES; 137 | } 138 | 139 | - (void) updateLoginButton 140 | { 141 | NSLog(@"Yay"); 142 | self.navigationItem.rightBarButtonItem.enabled = ([_usernameTextField.text length] != 0 && [_passwordTextField.text length] != 0); 143 | } 144 | 145 | #pragma mark - 146 | 147 | - (void) twitterAuthenticator: (TwitterAuthenticator*) twitterAuthenticator didFailWithError: (NSError*) error; 148 | { 149 | NSLog(@"TwitterAuthenticatorViewController#twitterAuthenticator: %@ didFailWithError: %@", twitterAuthenticator, error); 150 | 151 | self.navigationItem.rightBarButtonItem.enabled = YES; 152 | [self _showLoginForm]; 153 | [self _hideStatus]; 154 | 155 | [_delegate twitterLoginViewController: self didFailWithError: error]; 156 | } 157 | 158 | - (void) twitterAuthenticator: (TwitterAuthenticator*) twitterAuthenticator didSucceedWithToken: (TwitterToken*) token 159 | { 160 | NSLog(@"TwitterAuthenticatorViewController#twitterAuthenticator: %@ didSucceedWithToken: %@", twitterAuthenticator, token); 161 | 162 | self.navigationItem.rightBarButtonItem.enabled = YES; 163 | [self _showLoginForm]; 164 | [self _hideStatus]; 165 | 166 | [_delegate twitterLoginViewController: self didSucceedWithToken: token]; 167 | } 168 | 169 | #pragma mark - 170 | 171 | - (void) dealloc 172 | { 173 | [_authenticator release]; 174 | [super dealloc]; 175 | } 176 | 177 | @end -------------------------------------------------------------------------------- /Sources/TwitterLoginViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10F569 6 | 788 7 | 1038.29 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 117 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | 42 | 274 43 | 44 | YES 45 | 46 | 47 | 256 48 | {320, 416} 49 | 50 | 51 | 3 52 | MCAwAA 53 | 54 | NO 55 | YES 56 | 4 57 | YES 58 | IBCocoaTouchFramework 59 | 60 | NSImage 61 | TwitterClouds.png 62 | 63 | 64 | 65 | 66 | 274 67 | 68 | YES 69 | 70 | 71 | 292 72 | {{11, 23}, {120, 21}} 73 | 74 | NO 75 | YES 76 | 7 77 | NO 78 | IBCocoaTouchFramework 79 | #Username# 80 | 81 | Helvetica-Bold 82 | 17 83 | 16 84 | 85 | 86 | 1 87 | MCAwIDAAA 88 | 89 | 90 | 1 91 | 10 92 | 93 | 94 | 95 | 292 96 | {{11, 68}, {120, 21}} 97 | 98 | NO 99 | YES 100 | 7 101 | NO 102 | IBCocoaTouchFramework 103 | #Password# 104 | 105 | 106 | 107 | 1 108 | 10 109 | 110 | 111 | 112 | 292 113 | {{139, 20}, {129, 31}} 114 | 115 | NO 116 | YES 117 | IBCocoaTouchFramework 118 | 0 119 | 120 | 3 121 | #Required# 122 | 123 | 3 124 | MAA 125 | 126 | 2 127 | 128 | 129 | 130 | Helvetica 131 | 17 132 | 16 133 | 134 | YES 135 | 17 136 | 137 | 1 138 | IBCocoaTouchFramework 139 | 140 | 1 141 | 142 | 143 | 144 | 292 145 | {{139, 68}, {129, 31}} 146 | 147 | NO 148 | YES 149 | IBCocoaTouchFramework 150 | 0 151 | 152 | 3 153 | #Required# 154 | 155 | 3 156 | MAA 157 | 158 | 159 | 160 | YES 161 | 17 162 | 163 | 1 164 | YES 165 | IBCocoaTouchFramework 166 | 167 | 1 168 | 169 | 170 | 171 | 292 172 | {{20, 33}, {240, 26}} 173 | 174 | NO 175 | YES 176 | 7 177 | NO 178 | IBCocoaTouchFramework 179 | #SigningIn# 180 | 181 | Helvetica-Bold 182 | 19 183 | 16 184 | 185 | 186 | 187 | 1 188 | 10 189 | 1 190 | 191 | 192 | 193 | 292 194 | {{129, 60}, {20, 20}} 195 | 196 | NO 197 | IBCocoaTouchFramework 198 | NO 199 | 2 200 | 201 | 202 | {{20, 40}, {280, 119}} 203 | 204 | 205 | 3 206 | MQA 207 | 208 | 209 | IBCocoaTouchFramework 210 | 211 | 212 | 213 | 292 214 | {{36, 349}, {248, 37}} 215 | 216 | NO 217 | IBCocoaTouchFramework 218 | 0 219 | 0 220 | 221 | Helvetica-Bold 222 | 15 223 | 16 224 | 225 | 1 226 | #CreateATwitterAccount# 227 | 228 | 3 229 | MQA 230 | 231 | 232 | 1 233 | MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 234 | 235 | 236 | 3 237 | MC41AA 238 | 239 | 240 | 241 | {320, 416} 242 | 243 | 244 | 1 245 | MSAxIDEAA 246 | 247 | 248 | 249 | NO 250 | 251 | IBCocoaTouchFramework 252 | 253 | 254 | 255 | 256 | YES 257 | 258 | 259 | view 260 | 261 | 262 | 263 | 3 264 | 265 | 266 | 267 | _containerView 268 | 269 | 270 | 271 | 14 272 | 273 | 274 | 275 | _usernameTextField 276 | 277 | 278 | 279 | 15 280 | 281 | 282 | 283 | _passwordTextField 284 | 285 | 286 | 287 | 16 288 | 289 | 290 | 291 | _statusLabel 292 | 293 | 294 | 295 | 17 296 | 297 | 298 | 299 | _usernameLabel 300 | 301 | 302 | 303 | 18 304 | 305 | 306 | 307 | _passwordLabel 308 | 309 | 310 | 311 | 19 312 | 313 | 314 | 315 | delegate 316 | 317 | 318 | 319 | 20 320 | 321 | 322 | 323 | delegate 324 | 325 | 326 | 327 | 21 328 | 329 | 330 | 331 | _activityIndicatorView 332 | 333 | 334 | 335 | 31 336 | 337 | 338 | 339 | _createAccountButton 340 | 341 | 342 | 343 | 32 344 | 345 | 346 | 347 | 348 | YES 349 | 350 | 0 351 | 352 | 353 | 354 | 355 | 356 | 1 357 | 358 | 359 | YES 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | -1 368 | 369 | 370 | File's Owner 371 | 372 | 373 | -2 374 | 375 | 376 | 377 | 378 | 4 379 | 380 | 381 | YES 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 5 393 | 394 | 395 | 396 | 397 | 6 398 | 399 | 400 | 401 | 402 | 7 403 | 404 | 405 | 406 | 407 | 8 408 | 409 | 410 | 411 | 412 | 13 413 | 414 | 415 | 416 | 417 | 26 418 | 419 | 420 | 421 | 422 | 28 423 | 424 | 425 | 426 | 427 | 30 428 | 429 | 430 | 431 | 432 | 433 | 434 | YES 435 | 436 | YES 437 | -1.CustomClassName 438 | -2.CustomClassName 439 | 1.IBEditorWindowLastContentRect 440 | 1.IBPluginDependency 441 | 13.IBPluginDependency 442 | 26.IBPluginDependency 443 | 30.IBPluginDependency 444 | 4.IBPluginDependency 445 | 5.IBPluginDependency 446 | 6.IBPluginDependency 447 | 7.IBPluginDependency 448 | 8.IBPluginDependency 449 | 450 | 451 | YES 452 | TwitterLoginViewController 453 | UIResponder 454 | {{1068, 371}, {320, 480}} 455 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 456 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 457 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 458 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 459 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 460 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 461 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 462 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 463 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 464 | 465 | 466 | 467 | YES 468 | 469 | 470 | YES 471 | 472 | 473 | 474 | 475 | YES 476 | 477 | 478 | YES 479 | 480 | 481 | 482 | 32 483 | 484 | 485 | 486 | YES 487 | 488 | NSObject 489 | 490 | IBProjectSource 491 | ThirdPartySources/json-framework-2.2.3/Source/NSObject+SBJSON.h 492 | 493 | 494 | 495 | NSObject 496 | 497 | IBProjectSource 498 | ThirdPartySources/json-framework-2.2.3/Source/SBJsonWriter.h 499 | 500 | 501 | 502 | TwitterLoginViewController 503 | UIViewController 504 | 505 | YES 506 | 507 | YES 508 | cancel 509 | createAccount 510 | login 511 | 512 | 513 | YES 514 | id 515 | id 516 | id 517 | 518 | 519 | 520 | YES 521 | 522 | YES 523 | cancel 524 | createAccount 525 | login 526 | 527 | 528 | YES 529 | 530 | cancel 531 | id 532 | 533 | 534 | createAccount 535 | id 536 | 537 | 538 | login 539 | id 540 | 541 | 542 | 543 | 544 | YES 545 | 546 | YES 547 | _activityIndicatorView 548 | _containerView 549 | _createAccountButton 550 | _passwordLabel 551 | _passwordTextField 552 | _statusLabel 553 | _usernameLabel 554 | _usernameTextField 555 | 556 | 557 | YES 558 | UIActivityIndicatorView 559 | UIView 560 | UIButton 561 | UILabel 562 | UITextField 563 | UILabel 564 | UILabel 565 | UITextField 566 | 567 | 568 | 569 | YES 570 | 571 | YES 572 | _activityIndicatorView 573 | _containerView 574 | _createAccountButton 575 | _passwordLabel 576 | _passwordTextField 577 | _statusLabel 578 | _usernameLabel 579 | _usernameTextField 580 | 581 | 582 | YES 583 | 584 | _activityIndicatorView 585 | UIActivityIndicatorView 586 | 587 | 588 | _containerView 589 | UIView 590 | 591 | 592 | _createAccountButton 593 | UIButton 594 | 595 | 596 | _passwordLabel 597 | UILabel 598 | 599 | 600 | _passwordTextField 601 | UITextField 602 | 603 | 604 | _statusLabel 605 | UILabel 606 | 607 | 608 | _usernameLabel 609 | UILabel 610 | 611 | 612 | _usernameTextField 613 | UITextField 614 | 615 | 616 | 617 | 618 | IBProjectSource 619 | ThirdPartySources/iphone-twitter/Sources/TwitterLoginViewController.h 620 | 621 | 622 | 623 | 624 | 0 625 | IBCocoaTouchFramework 626 | 627 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 628 | 629 | 630 | 631 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 632 | 633 | 634 | YES 635 | ../../../DavidSuzuki.xcodeproj 636 | 3 637 | 638 | TwitterClouds.png 639 | {320, 416} 640 | 641 | 117 642 | 643 | 644 | -------------------------------------------------------------------------------- /Sources/TwitterRequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | @class TwitterToken; 23 | @class TwitterRequest; 24 | @class TwitterConsumer; 25 | 26 | @protocol TwitterRequestDelegate 27 | - (void) twitterRequest: (TwitterRequest*) request didFailWithError: (NSError*) error; 28 | - (void) twitterRequest:(TwitterRequest *)request didFinishLoadingData: (NSData*) data; 29 | @end 30 | 31 | @interface TwitterRequest : NSObject { 32 | @private 33 | TwitterConsumer* _twitterConsumer; 34 | NSDictionary* _parameters; 35 | TwitterToken* _token; 36 | NSURL* _url; 37 | NSURL* _realm; 38 | NSString* _method; 39 | id _delegate; 40 | @private 41 | NSURLConnection* _connection; 42 | NSMutableData* _data; 43 | NSInteger _statusCode; 44 | } 45 | 46 | @property (nonatomic,retain) TwitterConsumer* twitterConsumer; 47 | @property (nonatomic,retain) NSDictionary* parameters; 48 | @property (nonatomic,retain) TwitterToken* token; 49 | @property (nonatomic,retain) NSString* method; 50 | @property (nonatomic,retain) NSURL* url; 51 | @property (nonatomic,retain) NSURL* realm; 52 | @property (nonatomic,assign) id delegate; 53 | 54 | - (void) execute; 55 | - (void) cancel; 56 | 57 | @end -------------------------------------------------------------------------------- /Sources/TwitterRequest.m: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import "TwitterConsumer.h" 21 | #import "TwitterToken.h" 22 | #import "TwitterRequest.h" 23 | #import "TwitterUtils.h" 24 | 25 | @implementation TwitterRequest 26 | 27 | #pragma mark - 28 | 29 | @synthesize 30 | twitterConsumer = _twitterConsumer, 31 | parameters = _parameters, 32 | token = _token, 33 | method = _method, 34 | url = _url, 35 | realm = _realm, 36 | delegate = _delegate; 37 | 38 | #pragma mark - 39 | 40 | - (id) init 41 | { 42 | if ((self = [super init]) != nil) { 43 | } 44 | return self; 45 | } 46 | 47 | - (void) dealloc 48 | { 49 | [super dealloc]; 50 | } 51 | 52 | #pragma mark - 53 | 54 | - (NSString*) _generateTimestamp 55 | { 56 | return [NSString stringWithFormat: @"%d", time(NULL)]; 57 | } 58 | 59 | - (NSString*) _generateNonce 60 | { 61 | NSString* nonce = nil; 62 | 63 | CFUUIDRef uuid = CFUUIDCreate(nil); 64 | if (uuid != NULL) { 65 | nonce = (NSString*) CFUUIDCreateString(nil, uuid); 66 | CFRelease(uuid); 67 | } 68 | 69 | return [nonce autorelease]; 70 | } 71 | 72 | - (NSString*) _formEncodeString: (NSString*) string 73 | { 74 | NSString* encoded = (NSString*) CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 75 | (CFStringRef) string, NULL, CFSTR("!*'();:@&=+$,/?%#[]"), kCFStringEncodingUTF8); 76 | return [encoded autorelease]; 77 | } 78 | 79 | #pragma mark - 80 | 81 | - (void) execute 82 | { 83 | if (_connection == nil) 84 | { 85 | _data = [NSMutableData new]; 86 | 87 | NSString* timestamp = [self _generateTimestamp]; 88 | NSString* nonce = [self _generateNonce]; 89 | 90 | // Build a dictionary with all the parameters (oauth_* and call specific) 91 | 92 | NSMutableDictionary* parameters = [NSMutableDictionary dictionaryWithDictionary: _parameters]; 93 | 94 | [parameters setValue: _twitterConsumer.key forKey: @"oauth_consumer_key"]; 95 | [parameters setValue: @"HMAC-SHA1" forKey: @"oauth_signature_method"]; 96 | [parameters setValue: timestamp forKey: @"oauth_timestamp"]; 97 | [parameters setValue: nonce forKey: @"oauth_nonce"]; 98 | [parameters setValue: @"1.0" forKey: @"oauth_version"]; 99 | 100 | if (_token != nil) { 101 | [parameters setValue: _token.token forKey: @"oauth_token"]; 102 | } 103 | 104 | // Build the request string 105 | 106 | NSMutableString* normalizedRequestParameters = [NSMutableString string]; 107 | 108 | for (NSString* key in [[parameters allKeys] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)]) 109 | { 110 | if ([normalizedRequestParameters length] != 0) { 111 | [normalizedRequestParameters appendString: @"&"]; 112 | } 113 | 114 | [normalizedRequestParameters appendString: key]; 115 | [normalizedRequestParameters appendString: @"="]; 116 | [normalizedRequestParameters appendString: [self _formEncodeString: [parameters objectForKey: key]]]; 117 | } 118 | 119 | NSLog(@"XXX normalizedRequestParameters = %@", normalizedRequestParameters); 120 | 121 | // Create the signature base string 122 | 123 | NSString* signatureBaseString = [NSString stringWithFormat: @"%@&%@&%@", _method, 124 | [self _formEncodeString: [NSString stringWithFormat: @"%@://%@%@", [_url scheme], [_url host], [_url path]]], 125 | [self _formEncodeString: normalizedRequestParameters]]; 126 | 127 | NSLog(@"XXX signatureBaseString = %@", signatureBaseString); 128 | 129 | // Create the secret 130 | 131 | NSString* secret = nil; 132 | 133 | if (_token != nil) { 134 | secret = [NSString stringWithFormat:@"%@&%@", [self _formEncodeString: _twitterConsumer.secret], [self _formEncodeString: _token.secret]]; 135 | } else { 136 | secret = [NSString stringWithFormat:@"%@&", [self _formEncodeString: _twitterConsumer.secret]]; 137 | } 138 | 139 | NSLog(@"XXX Secret = %@", secret); 140 | 141 | // Set the signature parameter 142 | 143 | NSString* signatureString = [TwitterUtils encodeData: 144 | [TwitterUtils generateSignatureOverString: signatureBaseString withSecret: [secret dataUsingEncoding: NSASCIIStringEncoding]]]; 145 | 146 | // Add the signature to the request parameters (just the call specific ones) 147 | 148 | normalizedRequestParameters = [NSMutableString string]; 149 | 150 | for (NSString* key in [[_parameters allKeys] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)]) 151 | { 152 | if ([normalizedRequestParameters length] != 0) { 153 | [normalizedRequestParameters appendString: @"&"]; 154 | } 155 | 156 | [normalizedRequestParameters appendString: key]; 157 | [normalizedRequestParameters appendString: @"="]; 158 | [normalizedRequestParameters appendString: [self _formEncodeString: [_parameters objectForKey: key]]]; 159 | } 160 | 161 | NSLog(@"XXX POST Data = %@", normalizedRequestParameters); 162 | 163 | NSData* requestData = [normalizedRequestParameters dataUsingEncoding: NSUTF8StringEncoding]; 164 | 165 | // Setup the Authorization header 166 | 167 | NSMutableDictionary* authorizationParameters = [NSMutableDictionary dictionary]; 168 | 169 | [authorizationParameters setValue: nonce forKey: @"oauth_nonce"]; 170 | [authorizationParameters setValue: timestamp forKey: @"oauth_timestamp"]; 171 | [authorizationParameters setValue: signatureString forKey: @"oauth_signature"]; 172 | [authorizationParameters setValue: @"HMAC-SHA1" forKey: @"oauth_signature_method"]; 173 | [authorizationParameters setValue: @"1.0" forKey: @"oauth_version"]; 174 | [authorizationParameters setValue: _twitterConsumer.key forKey: @"oauth_consumer_key"]; 175 | 176 | if (_token != nil) { 177 | [authorizationParameters setValue: _token.token forKey: @"oauth_token"]; 178 | } 179 | 180 | NSMutableString* authorization = [NSMutableString stringWithString: @"OAuth realm=\"\""]; 181 | 182 | for (NSString* key in [authorizationParameters allKeys]) 183 | { 184 | // if ([authorization length] > 10) { 185 | [authorization appendString: @", "]; 186 | // } 187 | 188 | [authorization appendString: key]; 189 | [authorization appendString: @"="]; 190 | [authorization appendString: @"\""]; 191 | [authorization appendString: [self _formEncodeString: [authorizationParameters objectForKey: key]]]; 192 | [authorization appendString: @"\""]; 193 | } 194 | 195 | NSLog(@"Authorization: %@", authorization); 196 | 197 | // Setup the request and connection 198 | 199 | NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL: _url 200 | cachePolicy: NSURLRequestReloadIgnoringCacheData timeoutInterval: 15.0]; 201 | 202 | [request setHTTPMethod: _method]; 203 | [request setHTTPBody: requestData]; 204 | [request setValue: authorization forHTTPHeaderField: @"Authorization"]; 205 | [request setValue: [NSString stringWithFormat: @"%d", [requestData length]] forHTTPHeaderField: @"Content-Length"]; 206 | [request setValue: @"application/x-www-form-urlencoded" forHTTPHeaderField: @"Content-Type"]; 207 | 208 | _connection = [[NSURLConnection connectionWithRequest: request delegate: self] retain]; 209 | } 210 | } 211 | 212 | - (void) cancel 213 | { 214 | if (_connection != nil) { 215 | [_connection cancel]; 216 | [_connection release]; 217 | _connection = nil; 218 | } 219 | } 220 | 221 | #pragma mark - 222 | 223 | - (void) connection: (NSURLConnection*) connection didReceiveData: (NSData*) data 224 | { 225 | [_data appendData: data]; 226 | } 227 | 228 | - (void)connection: (NSURLConnection*) connection didReceiveResponse: (NSHTTPURLResponse*) response 229 | { 230 | _statusCode = [response statusCode]; 231 | } 232 | 233 | - (void) connection: (NSURLConnection*) connection didFailWithError: (NSError*) error 234 | { 235 | [_delegate twitterRequest: self didFailWithError: error]; 236 | 237 | [_connection release]; 238 | _connection = nil; 239 | 240 | [_data release]; 241 | _data = nil; 242 | } 243 | 244 | - (void) connectionDidFinishLoading: (NSURLConnection*) connection 245 | { 246 | if (_statusCode != 200) { 247 | NSLog(@"Request failed with status code %d", _statusCode); 248 | NSString* response = [[[NSString alloc] initWithData: _data encoding: NSUTF8StringEncoding] autorelease]; 249 | NSLog(@"Response = %@", response); 250 | // TODO: Real error handling 251 | [_delegate twitterRequest: self didFailWithError: nil]; 252 | } else { 253 | [_delegate twitterRequest: self didFinishLoadingData: _data]; 254 | } 255 | 256 | [_connection release]; 257 | _connection = nil; 258 | 259 | [_data release]; 260 | _data = nil; 261 | } 262 | 263 | @end 264 | -------------------------------------------------------------------------------- /Sources/TwitterToken.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | @interface TwitterToken : NSObject { 23 | @private 24 | NSString* _token; 25 | NSString* _secret; 26 | } 27 | 28 | @property (nonatomic,retain) NSString* token; 29 | @property (nonatomic,retain) NSString* secret; 30 | 31 | - (id) initWithToken: (NSString*) token secret: (NSString*) secret; 32 | 33 | @end -------------------------------------------------------------------------------- /Sources/TwitterToken.m: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import "TwitterToken.h" 21 | 22 | @implementation TwitterToken 23 | 24 | #pragma mark - 25 | 26 | @synthesize 27 | token = _token, 28 | secret = _secret; 29 | 30 | #pragma mark - 31 | 32 | - (id) initWithToken: (NSString*) token secret: (NSString*) secret 33 | { 34 | if ((self = [super init]) != nil) { 35 | _token = [token retain]; 36 | _secret = [secret retain]; 37 | } 38 | return self; 39 | } 40 | 41 | - (void) dealloc 42 | { 43 | [_token release]; 44 | [_secret release]; 45 | [super dealloc]; 46 | } 47 | 48 | #pragma mark - 49 | 50 | - (id) initWithCoder: (NSCoder*) coder 51 | { 52 | if ((self = [super init]) != nil) { 53 | _token = [[coder decodeObjectForKey: @"token"] retain]; 54 | _secret = [[coder decodeObjectForKey: @"secret"] retain]; 55 | } 56 | return self; 57 | } 58 | 59 | - (void) encodeWithCoder: (NSCoder*) coder 60 | { 61 | [coder encodeObject: _token forKey: @"token"]; 62 | [coder encodeObject: _secret forKey: @"secret"]; 63 | } 64 | 65 | #pragma mark - 66 | 67 | - (NSString*) description 68 | { 69 | return [NSString stringWithFormat: @"", self, _token, _secret]; 70 | } 71 | 72 | @end -------------------------------------------------------------------------------- /Sources/TwitterTweetPoster.h: -------------------------------------------------------------------------------- 1 | // TwitterTweetPoster.h 2 | 3 | #import 4 | 5 | #import "TwitterRequest.h" 6 | 7 | @class TwitterTweetPoster; 8 | @class TwitterConsumer; 9 | @class TwitterToken; 10 | 11 | @protocol TwitterTweetPosterDelegate 12 | - (void) twitterTweetPosterDidSucceed: (TwitterTweetPoster*) twitterTweetPoster; 13 | - (void) twitterTweetPoster: (TwitterTweetPoster*) twitterTweetPoster didFailWithError: (NSError*) error; 14 | @end 15 | 16 | @interface TwitterTweetPoster : NSObject { 17 | @private 18 | TwitterConsumer* _consumer; 19 | TwitterToken* _token; 20 | id _delegate; 21 | NSString* _message; 22 | @private 23 | TwitterRequest* _request; 24 | } 25 | 26 | @property (nonatomic,retain) TwitterConsumer* consumer; 27 | @property (nonatomic,retain) TwitterToken* token; 28 | @property (nonatomic,retain) id delegate; 29 | @property (nonatomic,retain) NSString* message; 30 | 31 | - (void) execute; 32 | - (void) cancel; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Sources/TwitterTweetPoster.m: -------------------------------------------------------------------------------- 1 | // TwitterTweetPoster.m 2 | 3 | #import "TwitterToken.h" 4 | #import "TwitterConsumer.h" 5 | #import "TwitterRequest.h" 6 | 7 | #import "TwitterTweetPoster.h" 8 | 9 | @implementation TwitterTweetPoster 10 | 11 | #pragma mark - 12 | 13 | @synthesize consumer = _consumer, token = _token, delegate = _delegate, message = _message; 14 | 15 | #pragma mark - 16 | 17 | - (id) init 18 | { 19 | if ((self = [super init]) != nil) { 20 | } 21 | return self; 22 | } 23 | 24 | - (void) dealloc 25 | { 26 | [_request release]; 27 | [_delegate release]; 28 | [super dealloc]; 29 | } 30 | 31 | #pragma mark - 32 | 33 | - (void) execute 34 | { 35 | if (_request == nil) 36 | { 37 | _request = [TwitterRequest new]; 38 | if (_request != nil) { 39 | _request.url = [NSURL URLWithString: @"http://api.twitter.com/1/statuses/update.xml"]; 40 | _request.twitterConsumer = _consumer; 41 | _request.token = _token; 42 | _request.method = @"POST"; 43 | _request.parameters = [NSDictionary dictionaryWithObjectsAndKeys: _message, @"status", nil]; 44 | _request.delegate = self; 45 | [_request execute]; 46 | } 47 | } 48 | } 49 | 50 | - (void) cancel 51 | { 52 | if (_request != nil) { 53 | [_request cancel]; 54 | [_request release]; 55 | _request = nil; 56 | } 57 | } 58 | 59 | #pragma mark - 60 | 61 | - (void) twitterRequest: (TwitterRequest*) request didFailWithError: (NSError*) error 62 | { 63 | [_delegate twitterTweetPoster: self didFailWithError: error]; 64 | } 65 | 66 | - (void) twitterRequest:(TwitterRequest *)request didFinishLoadingData: (NSData*) data 67 | { 68 | [_delegate twitterTweetPosterDidSucceed: self]; 69 | } 70 | 71 | @end -------------------------------------------------------------------------------- /Sources/TwitterUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #import 21 | 22 | @interface TwitterUtils : NSObject { 23 | 24 | } 25 | 26 | + (NSString*) encodeData: (NSData*) data; 27 | + (NSData*) generateSignatureOverString: (NSString*) string withSecret: (NSData*) secret; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Sources/TwitterUtils.m: -------------------------------------------------------------------------------- 1 | /* 2 | * (C) Copyright 2010, Stefan Arentz, Arentz Consulting Inc. 3 | * 4 | * Licensed to the Apache Software Foundation (ASF) under one or more 5 | * contributor license agreements. See the NOTICE file distributed with 6 | * this work for additional information regarding copyright ownership. 7 | * The ASF licenses this file to You under the Apache License, Version 2.0 8 | * (the "License"); you may not use this file except in compliance with 9 | * the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | 22 | #import "TwitterUtils.h" 23 | 24 | @implementation TwitterUtils 25 | 26 | static const char sBase64Digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 27 | 28 | + (NSString*) encodeData: (NSData*) data 29 | { 30 | if (data == nil) { 31 | return nil; 32 | } 33 | 34 | NSUInteger dataLength = [data length]; 35 | const UInt8* dataBytePtr = [data bytes]; 36 | 37 | NSUInteger encodedLength = (dataLength / 3) * 4; 38 | if ((dataLength % 3) != 0) { 39 | encodedLength += 4; 40 | } 41 | 42 | NSMutableString* string = [NSMutableString stringWithCapacity: encodedLength]; 43 | 44 | char buffer[5]; 45 | 46 | while (dataLength >= 3) 47 | { 48 | buffer[0] = sBase64Digits[dataBytePtr[0] >> 2]; 49 | buffer[1] = sBase64Digits[((dataBytePtr[0] << 4) & 0x30) | (dataBytePtr[1] >> 4)]; 50 | buffer[2] = sBase64Digits[((dataBytePtr[1] << 2) & 0x3c) | (dataBytePtr[2] >> 6)]; 51 | buffer[3] = sBase64Digits[dataBytePtr[2] & 0x3f]; 52 | buffer[4] = 0x00; 53 | 54 | [string appendString: [NSString stringWithCString: buffer encoding: NSASCIIStringEncoding]]; 55 | 56 | dataBytePtr += 3; 57 | dataLength -= 3; 58 | } 59 | 60 | if (dataLength > 0) 61 | { 62 | char fragment = (dataBytePtr[0] << 4) & 0x30; 63 | if (dataLength > 1) { 64 | fragment |= dataBytePtr[1] >> 4; 65 | } 66 | 67 | buffer[0] = sBase64Digits[dataBytePtr[0] >> 2]; 68 | buffer[1] = sBase64Digits[(int) fragment]; 69 | buffer[2] = (dataLength < 2) ? '=' : sBase64Digits[(dataBytePtr[1] << 2) & 0x3c]; 70 | buffer[3] = '='; 71 | buffer[4] = 0x00; 72 | 73 | [string appendString: [NSString stringWithCString: buffer encoding: NSASCIIStringEncoding]]; 74 | } 75 | 76 | return string; 77 | } 78 | 79 | + (NSData*) generateSignatureOverString: (NSString*) string withSecret: (NSData*) secret 80 | { 81 | CCHmacContext context; 82 | CCHmacInit(&context, kCCHmacAlgSHA1, [secret bytes], [secret length]); 83 | 84 | NSData* data = [string dataUsingEncoding: NSASCIIStringEncoding]; 85 | CCHmacUpdate(&context, [data bytes], [data length]); 86 | 87 | unsigned char digestBytes[CC_SHA1_DIGEST_LENGTH]; 88 | CCHmacFinal(&context, digestBytes); 89 | 90 | return [NSData dataWithBytes: digestBytes length: CC_SHA1_DIGEST_LENGTH]; 91 | } 92 | 93 | @end 94 | --------------------------------------------------------------------------------