From dd1e62990fc5e6249782da1a89cac149dc54a6a8 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Tue, 6 Jul 2010 14:17:06 -0700 Subject: [PATCH 01/50] initial commit --- Classes/Example/ExampleShareFile.h | 38 + Classes/Example/ExampleShareFile.m | 82 + Classes/Example/ExampleShareImage.h | 38 + Classes/Example/ExampleShareImage.m | 83 + Classes/Example/ExampleShareLink.h | 38 + Classes/Example/ExampleShareLink.m | 78 + Classes/Example/ExampleShareText.h | 38 + Classes/Example/ExampleShareText.m | 91 + Classes/Example/RootViewController.h | 14 + Classes/Example/RootViewController.m | 105 ++ Classes/Example/ShareKitAppDelegate.h | 21 + Classes/Example/ShareKitAppDelegate.m | 66 + Classes/Example/example.pdf | Bin 0 -> 73705 bytes Classes/Example/sanFran.jpg | Bin 0 -> 34943 bytes .../NSMutableURLRequest+Parameters.h | 35 + .../NSMutableURLRequest+Parameters.m | 97 ++ .../OAuth/Categories/NSString+URLEncoding.h | 34 + .../OAuth/Categories/NSString+URLEncoding.m | 52 + Classes/OAuth/Categories/NSURL+Base.h | 34 + Classes/OAuth/Categories/NSURL+Base.m | 38 + Classes/OAuth/Crytpo/Base64Transcoder.c | 230 +++ Classes/OAuth/Crytpo/Base64Transcoder.h | 36 + Classes/OAuth/Crytpo/hmac.c | 86 + Classes/OAuth/Crytpo/hmac.h | 31 + Classes/OAuth/Crytpo/sha1.c | 169 ++ Classes/OAuth/Crytpo/sha1.h | 12 + Classes/OAuth/OAAsynchronousDataFetcher.h | 45 + Classes/OAuth/OAAsynchronousDataFetcher.m | 134 ++ Classes/OAuth/OAConsumer.h | 40 + Classes/OAuth/OAConsumer.m | 51 + Classes/OAuth/OADataFetcher.h | 45 + Classes/OAuth/OADataFetcher.m | 65 + Classes/OAuth/OAHMAC_SHA1SignatureProvider.h | 32 + Classes/OAuth/OAHMAC_SHA1SignatureProvider.m | 58 + Classes/OAuth/OAMutableURLRequest.h | 68 + Classes/OAuth/OAMutableURLRequest.m | 231 +++ Classes/OAuth/OAPlaintextSignatureProvider.h | 31 + Classes/OAuth/OAPlaintextSignatureProvider.m | 43 + Classes/OAuth/OAProblem.h | 53 + Classes/OAuth/OAProblem.m | 165 ++ Classes/OAuth/OARequestParameter.h | 45 + Classes/OAuth/OARequestParameter.m | 70 + Classes/OAuth/OAServiceTicket.h | 47 + Classes/OAuth/OAServiceTicket.m | 56 + Classes/OAuth/OASignatureProviding.h | 34 + Classes/OAuth/OAToken.h | 41 + Classes/OAuth/OAToken.m | 105 ++ Classes/OAuth/OAuthConsumer.h | 39 + .../Core/Base Sharer Classes/SHKOAuthSharer.h | 89 + .../Core/Base Sharer Classes/SHKOAuthSharer.m | 272 +++ .../Core/Base Sharer Classes/SHKSharer.h | 172 ++ .../Core/Base Sharer Classes/SHKSharer.m | 666 ++++++++ .../ShareKit/Core/Categories/UIWebView+SHK.h | 38 + .../ShareKit/Core/Categories/UIWebView+SHK.m | 37 + .../Core/Helpers/Keychain/SFHFKeychainUtils.h | 41 + .../Core/Helpers/Keychain/SFHFKeychainUtils.m | 434 +++++ .../NSMutableURLRequest+Parameters.h | 35 + .../NSMutableURLRequest+Parameters.m | 97 ++ .../OAuth/Categories/NSString+URLEncoding.h | 34 + .../OAuth/Categories/NSString+URLEncoding.m | 52 + .../Helpers/OAuth/Categories/NSURL+Base.h | 34 + .../Helpers/OAuth/Categories/NSURL+Base.m | 38 + .../Helpers/OAuth/Crytpo/Base64Transcoder.c | 230 +++ .../Helpers/OAuth/Crytpo/Base64Transcoder.h | 36 + .../ShareKit/Core/Helpers/OAuth/Crytpo/hmac.c | 86 + .../ShareKit/Core/Helpers/OAuth/Crytpo/hmac.h | 31 + .../ShareKit/Core/Helpers/OAuth/Crytpo/sha1.c | 169 ++ .../ShareKit/Core/Helpers/OAuth/Crytpo/sha1.h | 12 + .../Helpers/OAuth/OAAsynchronousDataFetcher.h | 45 + .../Helpers/OAuth/OAAsynchronousDataFetcher.m | 134 ++ .../ShareKit/Core/Helpers/OAuth/OAConsumer.h | 40 + .../ShareKit/Core/Helpers/OAuth/OAConsumer.m | 51 + .../Core/Helpers/OAuth/OADataFetcher.h | 45 + .../Core/Helpers/OAuth/OADataFetcher.m | 65 + .../OAuth/OAHMAC_SHA1SignatureProvider.h | 32 + .../OAuth/OAHMAC_SHA1SignatureProvider.m | 58 + .../Core/Helpers/OAuth/OAMutableURLRequest.h | 68 + .../Core/Helpers/OAuth/OAMutableURLRequest.m | 231 +++ .../OAuth/OAPlaintextSignatureProvider.h | 31 + .../OAuth/OAPlaintextSignatureProvider.m | 43 + .../ShareKit/Core/Helpers/OAuth/OAProblem.h | 53 + .../ShareKit/Core/Helpers/OAuth/OAProblem.m | 165 ++ .../Core/Helpers/OAuth/OARequestParameter.h | 45 + .../Core/Helpers/OAuth/OARequestParameter.m | 70 + .../Core/Helpers/OAuth/OAServiceTicket.h | 47 + .../Core/Helpers/OAuth/OAServiceTicket.m | 56 + .../Core/Helpers/OAuth/OASignatureProviding.h | 34 + Classes/ShareKit/Core/Helpers/OAuth/OAToken.h | 41 + Classes/ShareKit/Core/Helpers/OAuth/OAToken.m | 105 ++ .../Core/Helpers/OAuth/OAuthConsumer.h | 39 + Classes/ShareKit/Core/Helpers/SHKRequest.h | 74 + Classes/ShareKit/Core/Helpers/SHKRequest.m | 148 ++ Classes/ShareKit/Core/SHK.h | 120 ++ Classes/ShareKit/Core/SHK.m | 460 ++++++ Classes/ShareKit/Core/SHKItem.h | 86 + Classes/ShareKit/Core/SHKItem.m | 183 ++ Classes/ShareKit/Core/SHKOfflineSharer.h | 56 + Classes/ShareKit/Core/SHKOfflineSharer.m | 153 ++ Classes/ShareKit/Core/SHKSharers.plist | 21 + .../Customize UI/SHKCustomFormController.h | 35 + .../Customize UI/SHKCustomFormController.m | 133 ++ .../Customize UI/SHKCustomFormFieldCell.h | 36 + .../Customize UI/SHKCustomFormFieldCell.m | 35 + .../Customize UI/SHKCustomShareMenu.h | 40 + .../Customize UI/SHKCustomShareMenu.m | 36 + .../Customize UI/SHKCustomShareMenuCell.h | 45 + .../Customize UI/SHKCustomShareMenuCell.m | 35 + Classes/ShareKit/Reachability/Reachability.h | 88 + Classes/ShareKit/Reachability/Reachability.m | 273 +++ Classes/ShareKit/SHKConfig.h | 127 ++ .../ShareKit/Sharers/Actions/Copy/SHKCopy.h | 36 + .../ShareKit/Sharers/Actions/Copy/SHKCopy.m | 88 + .../ShareKit/Sharers/Actions/Email/SHKMail.h | 46 + .../ShareKit/Sharers/Actions/Email/SHKMail.m | 186 +++ .../Actions/Open in Safari/SHKSafari.h | 36 + .../Actions/Open in Safari/SHKSafari.m | 79 + .../Sharers/Services/Delicious/SHKDelicious.h | 41 + .../Sharers/Services/Delicious/SHKDelicious.m | 193 +++ .../FBConnect.bundle/images/close.png | Bin 0 -> 164 bytes .../FBConnect.bundle/images/fbicon.png | Bin 0 -> 226 bytes .../FBConnect.bundle/images/login.png | Bin 0 -> 2102 bytes .../FBConnect.bundle/images/login2.png | Bin 0 -> 3843 bytes .../FBConnect.bundle/images/login2_down.png | Bin 0 -> 3728 bytes .../FBConnect.bundle/images/login_down.png | Bin 0 -> 1980 bytes .../FBConnect.bundle/images/logout.png | Bin 0 -> 1661 bytes .../FBConnect.bundle/images/logout_down.png | Bin 0 -> 1551 bytes .../Services/Facebook/FBConnect/FBConnect.h | 23 + .../Facebook/FBConnect/FBConnectGlobal.h | 213 +++ .../Facebook/FBConnect/FBConnectGlobal.m | 33 + .../Services/Facebook/FBConnect/FBDialog.h | 137 ++ .../Services/Facebook/FBConnect/FBDialog.m | 606 +++++++ .../Facebook/FBConnect/FBFeedDialog.h | 42 + .../Facebook/FBConnect/FBFeedDialog.m | 85 + .../Facebook/FBConnect/FBLoginButton.h | 49 + .../Facebook/FBConnect/FBLoginButton.m | 162 ++ .../Facebook/FBConnect/FBLoginDialog.h | 24 + .../Facebook/FBConnect/FBLoginDialog.m | 129 ++ .../Facebook/FBConnect/FBPermissionDialog.h | 31 + .../Facebook/FBConnect/FBPermissionDialog.m | 100 ++ .../Services/Facebook/FBConnect/FBRequest.h | 165 ++ .../Services/Facebook/FBConnect/FBRequest.m | 378 +++++ .../Services/Facebook/FBConnect/FBSession.h | 188 +++ .../Services/Facebook/FBConnect/FBSession.m | 286 ++++ .../Facebook/FBConnect/FBStreamDialog.h | 62 + .../Facebook/FBConnect/FBStreamDialog.m | 77 + .../Facebook/FBConnect/FBXMLHandler.h | 32 + .../Facebook/FBConnect/FBXMLHandler.m | 152 ++ .../Sharers/Services/Facebook/SHKFacebook.h | 52 + .../Sharers/Services/Facebook/SHKFacebook.m | 218 +++ .../Services/Google Reader/SHKGoogleReader.h | 44 + .../Services/Google Reader/SHKGoogleReader.m | 301 ++++ .../Sharers/Services/Pinboard/SHKPinboard.h | 36 + .../Sharers/Services/Pinboard/SHKPinboard.m | 173 ++ .../Services/Read It Later/SHKReadItLater.h | 35 + .../Services/Read It Later/SHKReadItLater.m | 188 +++ .../Sharers/Services/Twitter/SHKTwitter.h | 61 + .../Sharers/Services/Twitter/SHKTwitter.m | 379 +++++ .../Sharers/Services/Twitter/SHKTwitterForm.h | 44 + .../Sharers/Services/Twitter/SHKTwitterForm.m | 212 +++ Classes/ShareKit/UI/SHKActionSheet.h | 46 + Classes/ShareKit/UI/SHKActionSheet.m | 102 ++ Classes/ShareKit/UI/SHKActivityIndicator.h | 59 + Classes/ShareKit/UI/SHKActivityIndicator.m | 277 ++++ Classes/ShareKit/UI/SHKFormController.h | 82 + Classes/ShareKit/UI/SHKFormController.m | 288 ++++ Classes/ShareKit/UI/SHKFormFieldCell.h | 61 + Classes/ShareKit/UI/SHKFormFieldCell.m | 156 ++ Classes/ShareKit/UI/SHKFormFieldSettings.h | 55 + Classes/ShareKit/UI/SHKFormFieldSettings.m | 54 + Classes/ShareKit/UI/SHKNavController.h | 36 + Classes/ShareKit/UI/SHKNavController.m | 38 + Classes/ShareKit/UI/SHKOAuthView.h | 57 + Classes/ShareKit/UI/SHKOAuthView.m | 158 ++ Classes/ShareKit/UI/SHKShareMenu.h | 56 + Classes/ShareKit/UI/SHKShareMenu.m | 325 ++++ .../ShareKit/UI/SHKViewControllerWrapper.h | 35 + .../ShareKit/UI/SHKViewControllerWrapper.m | 38 + MainWindow.xib | 279 ++++ RootViewController.xib | 384 +++++ ShareKit-Info.plist | 30 + ShareKit.xcodeproj/nate.mode1v3 | 1469 ++++++++++++++++ ShareKit.xcodeproj/nate.pbxuser | 1472 +++++++++++++++++ ShareKit.xcodeproj/project.pbxproj | 892 ++++++++++ ShareKit_Prefix.pch | 14 + main.m | 17 + 185 files changed, 21231 insertions(+) create mode 100644 Classes/Example/ExampleShareFile.h create mode 100644 Classes/Example/ExampleShareFile.m create mode 100644 Classes/Example/ExampleShareImage.h create mode 100644 Classes/Example/ExampleShareImage.m create mode 100644 Classes/Example/ExampleShareLink.h create mode 100644 Classes/Example/ExampleShareLink.m create mode 100644 Classes/Example/ExampleShareText.h create mode 100644 Classes/Example/ExampleShareText.m create mode 100644 Classes/Example/RootViewController.h create mode 100644 Classes/Example/RootViewController.m create mode 100644 Classes/Example/ShareKitAppDelegate.h create mode 100644 Classes/Example/ShareKitAppDelegate.m create mode 100644 Classes/Example/example.pdf create mode 100644 Classes/Example/sanFran.jpg create mode 100755 Classes/OAuth/Categories/NSMutableURLRequest+Parameters.h create mode 100755 Classes/OAuth/Categories/NSMutableURLRequest+Parameters.m create mode 100755 Classes/OAuth/Categories/NSString+URLEncoding.h create mode 100755 Classes/OAuth/Categories/NSString+URLEncoding.m create mode 100755 Classes/OAuth/Categories/NSURL+Base.h create mode 100755 Classes/OAuth/Categories/NSURL+Base.m create mode 100755 Classes/OAuth/Crytpo/Base64Transcoder.c create mode 100755 Classes/OAuth/Crytpo/Base64Transcoder.h create mode 100755 Classes/OAuth/Crytpo/hmac.c create mode 100755 Classes/OAuth/Crytpo/hmac.h create mode 100755 Classes/OAuth/Crytpo/sha1.c create mode 100755 Classes/OAuth/Crytpo/sha1.h create mode 100644 Classes/OAuth/OAAsynchronousDataFetcher.h create mode 100644 Classes/OAuth/OAAsynchronousDataFetcher.m create mode 100755 Classes/OAuth/OAConsumer.h create mode 100755 Classes/OAuth/OAConsumer.m create mode 100755 Classes/OAuth/OADataFetcher.h create mode 100755 Classes/OAuth/OADataFetcher.m create mode 100755 Classes/OAuth/OAHMAC_SHA1SignatureProvider.h create mode 100755 Classes/OAuth/OAHMAC_SHA1SignatureProvider.m create mode 100755 Classes/OAuth/OAMutableURLRequest.h create mode 100755 Classes/OAuth/OAMutableURLRequest.m create mode 100755 Classes/OAuth/OAPlaintextSignatureProvider.h create mode 100755 Classes/OAuth/OAPlaintextSignatureProvider.m create mode 100755 Classes/OAuth/OAProblem.h create mode 100755 Classes/OAuth/OAProblem.m create mode 100755 Classes/OAuth/OARequestParameter.h create mode 100755 Classes/OAuth/OARequestParameter.m create mode 100755 Classes/OAuth/OAServiceTicket.h create mode 100755 Classes/OAuth/OAServiceTicket.m create mode 100755 Classes/OAuth/OASignatureProviding.h create mode 100755 Classes/OAuth/OAToken.h create mode 100755 Classes/OAuth/OAToken.m create mode 100755 Classes/OAuth/OAuthConsumer.h create mode 100644 Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.h create mode 100644 Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m create mode 100644 Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h create mode 100644 Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m create mode 100644 Classes/ShareKit/Core/Categories/UIWebView+SHK.h create mode 100644 Classes/ShareKit/Core/Categories/UIWebView+SHK.m create mode 100644 Classes/ShareKit/Core/Helpers/Keychain/SFHFKeychainUtils.h create mode 100644 Classes/ShareKit/Core/Helpers/Keychain/SFHFKeychainUtils.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Categories/NSMutableURLRequest+Parameters.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Categories/NSMutableURLRequest+Parameters.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Categories/NSString+URLEncoding.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Categories/NSString+URLEncoding.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Categories/NSURL+Base.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Categories/NSURL+Base.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Crytpo/Base64Transcoder.c create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Crytpo/Base64Transcoder.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Crytpo/hmac.c create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Crytpo/hmac.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Crytpo/sha1.c create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/Crytpo/sha1.h create mode 100644 Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.h create mode 100644 Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAConsumer.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAConsumer.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OADataFetcher.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OADataFetcher.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAHMAC_SHA1SignatureProvider.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAHMAC_SHA1SignatureProvider.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAPlaintextSignatureProvider.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAPlaintextSignatureProvider.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAProblem.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAProblem.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OARequestParameter.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OARequestParameter.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAServiceTicket.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAServiceTicket.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OASignatureProviding.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAToken.h create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAToken.m create mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAuthConsumer.h create mode 100644 Classes/ShareKit/Core/Helpers/SHKRequest.h create mode 100644 Classes/ShareKit/Core/Helpers/SHKRequest.m create mode 100644 Classes/ShareKit/Core/SHK.h create mode 100644 Classes/ShareKit/Core/SHK.m create mode 100644 Classes/ShareKit/Core/SHKItem.h create mode 100644 Classes/ShareKit/Core/SHKItem.m create mode 100644 Classes/ShareKit/Core/SHKOfflineSharer.h create mode 100644 Classes/ShareKit/Core/SHKOfflineSharer.m create mode 100644 Classes/ShareKit/Core/SHKSharers.plist create mode 100644 Classes/ShareKit/Customize UI/SHKCustomFormController.h create mode 100644 Classes/ShareKit/Customize UI/SHKCustomFormController.m create mode 100644 Classes/ShareKit/Customize UI/SHKCustomFormFieldCell.h create mode 100644 Classes/ShareKit/Customize UI/SHKCustomFormFieldCell.m create mode 100644 Classes/ShareKit/Customize UI/SHKCustomShareMenu.h create mode 100644 Classes/ShareKit/Customize UI/SHKCustomShareMenu.m create mode 100644 Classes/ShareKit/Customize UI/SHKCustomShareMenuCell.h create mode 100644 Classes/ShareKit/Customize UI/SHKCustomShareMenuCell.m create mode 100644 Classes/ShareKit/Reachability/Reachability.h create mode 100644 Classes/ShareKit/Reachability/Reachability.m create mode 100644 Classes/ShareKit/SHKConfig.h create mode 100644 Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.h create mode 100644 Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m create mode 100644 Classes/ShareKit/Sharers/Actions/Email/SHKMail.h create mode 100644 Classes/ShareKit/Sharers/Actions/Email/SHKMail.m create mode 100644 Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.h create mode 100644 Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m create mode 100644 Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.h create mode 100644 Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/close.png create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/fbicon.png create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2_down.png create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login_down.png create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout.png create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m create mode 100755 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h create mode 100755 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m create mode 100644 Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.h create mode 100644 Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m create mode 100644 Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.h create mode 100644 Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m create mode 100644 Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.h create mode 100644 Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m create mode 100644 Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h create mode 100644 Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m create mode 100644 Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.h create mode 100644 Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m create mode 100644 Classes/ShareKit/UI/SHKActionSheet.h create mode 100644 Classes/ShareKit/UI/SHKActionSheet.m create mode 100644 Classes/ShareKit/UI/SHKActivityIndicator.h create mode 100644 Classes/ShareKit/UI/SHKActivityIndicator.m create mode 100644 Classes/ShareKit/UI/SHKFormController.h create mode 100644 Classes/ShareKit/UI/SHKFormController.m create mode 100644 Classes/ShareKit/UI/SHKFormFieldCell.h create mode 100644 Classes/ShareKit/UI/SHKFormFieldCell.m create mode 100644 Classes/ShareKit/UI/SHKFormFieldSettings.h create mode 100644 Classes/ShareKit/UI/SHKFormFieldSettings.m create mode 100644 Classes/ShareKit/UI/SHKNavController.h create mode 100644 Classes/ShareKit/UI/SHKNavController.m create mode 100644 Classes/ShareKit/UI/SHKOAuthView.h create mode 100644 Classes/ShareKit/UI/SHKOAuthView.m create mode 100644 Classes/ShareKit/UI/SHKShareMenu.h create mode 100644 Classes/ShareKit/UI/SHKShareMenu.m create mode 100644 Classes/ShareKit/UI/SHKViewControllerWrapper.h create mode 100644 Classes/ShareKit/UI/SHKViewControllerWrapper.m create mode 100644 MainWindow.xib create mode 100644 RootViewController.xib create mode 100644 ShareKit-Info.plist create mode 100644 ShareKit.xcodeproj/nate.mode1v3 create mode 100644 ShareKit.xcodeproj/nate.pbxuser create mode 100755 ShareKit.xcodeproj/project.pbxproj create mode 100644 ShareKit_Prefix.pch create mode 100644 main.m diff --git a/Classes/Example/ExampleShareFile.h b/Classes/Example/ExampleShareFile.h new file mode 100644 index 00000000..43ce4379 --- /dev/null +++ b/Classes/Example/ExampleShareFile.h @@ -0,0 +1,38 @@ +// +// ExampleShareFile.h +// ShareKit +// +// Created by Nathan Weiner on 6/29/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface ExampleShareFile : UIViewController +{ + UIWebView *webView; +} + +@property (nonatomic, retain) UIWebView *webView; + +@end diff --git a/Classes/Example/ExampleShareFile.m b/Classes/Example/ExampleShareFile.m new file mode 100644 index 00000000..3a76c403 --- /dev/null +++ b/Classes/Example/ExampleShareFile.m @@ -0,0 +1,82 @@ +// +// ExampleShareFile.m +// ShareKit +// +// Created by Nathan Weiner on 6/29/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "ExampleShareFile.h" +#import "SHK.h" +#import "SHKActionSheet.h" + +@implementation ExampleShareFile + +@synthesize webView; + +- (void)dealloc +{ + [webView release]; + [super dealloc]; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) + { + self.toolbarItems = [NSArray arrayWithObjects: + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(share)] autorelease], + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + nil + ]; + } + + return self; +} + +- (void)loadView +{ + self.webView = [[UIWebView alloc] initWithFrame:CGRectZero]; + webView.delegate = self; + webView.scalesPageToFit = YES; + [webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"example.pdf"]]]]; + + self.view = webView; +} + +- (void)share +{ + NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"example.pdf"]; + NSData *file = [NSData dataWithContentsOfFile:filePath]; + + SHKItem *item = [SHKItem file:file filename:@"Awesome.pdf" mimeType:@"application/pdf" title:@"My Awesome PDF"]; + SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item]; + [actionSheet showFromToolbar:self.navigationController.toolbar]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + +@end diff --git a/Classes/Example/ExampleShareImage.h b/Classes/Example/ExampleShareImage.h new file mode 100644 index 00000000..10526ad9 --- /dev/null +++ b/Classes/Example/ExampleShareImage.h @@ -0,0 +1,38 @@ +// +// ExampleShareImage.h +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface ExampleShareImage : UIViewController +{ + UIImageView *imageView; +} + +@property (nonatomic, retain) UIImageView *imageView; + +@end diff --git a/Classes/Example/ExampleShareImage.m b/Classes/Example/ExampleShareImage.m new file mode 100644 index 00000000..e7031f0f --- /dev/null +++ b/Classes/Example/ExampleShareImage.m @@ -0,0 +1,83 @@ + // +// ExampleShareImage.m +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "ExampleShareImage.h" +#import "SHKItem.h" +#import "SHKActionSheet.h" + +@implementation ExampleShareImage + +@synthesize imageView; + +- (void)dealloc +{ + [imageView release]; + [super dealloc]; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) + { + self.toolbarItems = [NSArray arrayWithObjects: + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(share)] autorelease], + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + nil + ]; + } + + return self; +} + +- (void)loadView +{ + [super loadView]; + + self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"sanFran.jpg"]]; + + imageView.frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height); + + [self.view addSubview:imageView]; + + [imageView release]; +} + +- (void)share +{ + SHKItem *item = [SHKItem image:imageView.image title:@"San Francisco"]; + SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item]; + + [actionSheet showFromToolbar:self.navigationController.toolbar]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + +@end diff --git a/Classes/Example/ExampleShareLink.h b/Classes/Example/ExampleShareLink.h new file mode 100644 index 00000000..5fffd2a1 --- /dev/null +++ b/Classes/Example/ExampleShareLink.h @@ -0,0 +1,38 @@ +// +// ExampleShareLink.h +// ShareKit +// +// Created by Nathan Weiner on 6/17/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface ExampleShareLink : UIViewController +{ + UIWebView *webView; +} + +@property (nonatomic, retain) UIWebView *webView; + +@end diff --git a/Classes/Example/ExampleShareLink.m b/Classes/Example/ExampleShareLink.m new file mode 100644 index 00000000..cef5fe77 --- /dev/null +++ b/Classes/Example/ExampleShareLink.m @@ -0,0 +1,78 @@ + // +// ExampleShareLink.m +// ShareKit +// +// Created by Nathan Weiner on 6/17/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "ExampleShareLink.h" +#import "SHK.h" + +@implementation ExampleShareLink + +@synthesize webView; + +- (void)dealloc +{ + [webView release]; + [super dealloc]; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) + { + self.toolbarItems = [NSArray arrayWithObjects: + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(share)] autorelease], + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + nil + ]; + } + + return self; +} + +- (void)share +{ + SHKItem *item = [SHKItem URL:webView.request.URL title:[webView pageTitle]]; + SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item]; + [actionSheet showFromToolbar:self.navigationController.toolbar]; +} + +- (void)loadView +{ + self.webView = [[UIWebView alloc] initWithFrame:CGRectZero]; + webView.delegate = self; + webView.scalesPageToFit = YES; + [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://apple.com/"]]]; + + self.view = webView; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + +@end diff --git a/Classes/Example/ExampleShareText.h b/Classes/Example/ExampleShareText.h new file mode 100644 index 00000000..1625839b --- /dev/null +++ b/Classes/Example/ExampleShareText.h @@ -0,0 +1,38 @@ +// +// ExampleShareText.h +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface ExampleShareText : UIViewController +{ + UITextView *textView; +} + +@property (nonatomic, retain) UITextView *textView; + +@end diff --git a/Classes/Example/ExampleShareText.m b/Classes/Example/ExampleShareText.m new file mode 100644 index 00000000..cc66d29f --- /dev/null +++ b/Classes/Example/ExampleShareText.m @@ -0,0 +1,91 @@ + // +// ExampleShareText.m +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#import "ExampleShareText.h" +#import "SHKItem.h" +#import "SHKActionSheet.h" + +@implementation ExampleShareText + +@synthesize textView; + +- (void)dealloc +{ + [textView release]; + [super dealloc]; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) + { + self.toolbarItems = [NSArray arrayWithObjects: + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(share)] autorelease], + [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease], + nil + ]; + } + + return self; +} + +- (void)loadView +{ + [super loadView]; + + self.textView = [[UITextView alloc] initWithFrame:CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height)]; + [self.view addSubview:textView]; + + textView.text = @"This is a chunk of text. If you highlight it, you'll be able to share the selection. If you tap the share button below, it will share all of it."; + textView.editable = NO; + + [textView release]; +} + +- (void)share +{ + NSString *text; + + if (textView.selectedRange.length > 0) + text = [textView.text substringWithRange:textView.selectedRange]; + + else + text = textView.text; + + + SHKItem *item = [SHKItem text:text]; + SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item]; + + [actionSheet showFromToolbar:self.navigationController.toolbar]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + + +@end diff --git a/Classes/Example/RootViewController.h b/Classes/Example/RootViewController.h new file mode 100644 index 00000000..289d499a --- /dev/null +++ b/Classes/Example/RootViewController.h @@ -0,0 +1,14 @@ +// +// RootViewController.h +// ShareKit +// +// Created by Nathan Weiner on 6/4/10. +// Copyright Idea Shower, LLC 2010. All rights reserved. +// + +#import + +@interface RootViewController : UITableViewController { +} + +@end diff --git a/Classes/Example/RootViewController.m b/Classes/Example/RootViewController.m new file mode 100644 index 00000000..afbf2be1 --- /dev/null +++ b/Classes/Example/RootViewController.m @@ -0,0 +1,105 @@ +// +// RootViewController.m +// ShareKit +// +// Created by Nathan Weiner on 6/4/10. +// Copyright Idea Shower, LLC 2010. All rights reserved. +// + +#import "RootViewController.h" +#import "ExampleShareLink.h" +#import "ExampleShareImage.h" +#import "ExampleShareText.h" +#import "ExampleShareFile.h" +#import "SHK.h" + +@implementation RootViewController + +#pragma mark - +#pragma mark Table view data source + + +// Customize the number of sections in the table view. +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + + +// Customize the number of rows in the table view. +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return 4; +} + + +// Customize the appearance of table view cells. +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; + } + + switch (indexPath.row) + { + case 0: + cell.textLabel.text = @"Sharing a Link"; + break; + + case 1: + cell.textLabel.text = @"Sharing an Image"; + break; + + case 2: + cell.textLabel.text = @"Sharing Text"; + break; + + case 3: + cell.textLabel.text = @"Sharing a File"; + break; + + } + + return cell; +} + + +#pragma mark - +#pragma mark Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + switch (indexPath.row) + { + case 0: + [self.navigationController pushViewController:[[[ExampleShareLink alloc] initWithNibName:nil bundle:nil] autorelease] animated:YES]; + break; + + case 1: + [self.navigationController pushViewController:[[[ExampleShareImage alloc] initWithNibName:nil bundle:nil] autorelease] animated:YES]; + break; + + case 2: + [self.navigationController pushViewController:[[[ExampleShareText alloc] initWithNibName:nil bundle:nil] autorelease] animated:YES]; + break; + + case 3: + [self.navigationController pushViewController:[[[ExampleShareFile alloc] initWithNibName:nil bundle:nil] autorelease] animated:YES]; + break; + + + } +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + + + + +@end + diff --git a/Classes/Example/ShareKitAppDelegate.h b/Classes/Example/ShareKitAppDelegate.h new file mode 100644 index 00000000..0824f973 --- /dev/null +++ b/Classes/Example/ShareKitAppDelegate.h @@ -0,0 +1,21 @@ +// +// ShareKitAppDelegate.h +// ShareKit +// +// Created by Nathan Weiner on 6/4/10. +// Copyright Idea Shower, LLC 2010. All rights reserved. +// + +#import + +@interface ShareKitAppDelegate : NSObject { + + UIWindow *window; + UINavigationController *navigationController; +} + +@property (nonatomic, retain) IBOutlet UIWindow *window; +@property (nonatomic, retain) IBOutlet UINavigationController *navigationController; + +@end + diff --git a/Classes/Example/ShareKitAppDelegate.m b/Classes/Example/ShareKitAppDelegate.m new file mode 100644 index 00000000..01f51ae3 --- /dev/null +++ b/Classes/Example/ShareKitAppDelegate.m @@ -0,0 +1,66 @@ +// +// ShareKitAppDelegate.m +// ShareKit +// +// Created by Nathan Weiner on 6/4/10. +// Copyright Idea Shower, LLC 2010. All rights reserved. +// + +#import "ShareKitAppDelegate.h" +#import "RootViewController.h" + +#import "SHKReadItLater.h" +#import "SHKFacebook.h" + +@implementation ShareKitAppDelegate + +@synthesize window; +@synthesize navigationController; + + +#pragma mark - +#pragma mark Application lifecycle + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after app launch + + [window addSubview:[navigationController view]]; + [window makeKeyAndVisible]; + + navigationController.topViewController.title = @"Examples"; + [navigationController setToolbarHidden:NO]; + + [self performSelector:@selector(test) withObject:nil afterDelay:0.5]; + + return YES; +} + +- (void)test +{ + [SHK flushOfflineQueue]; + //[SHKFacebook shareURL:[NSURL URLWithString:@"http://ideashower.com"]]; +} + +- (void)test2 +{ + [[SHKActivityIndicator currentIndicator] displayCompleted:@"Saved!"]; +} + + +- (void)applicationWillTerminate:(UIApplication *)application { + // Save data if appropriate +} + + +#pragma mark - +#pragma mark Memory management + +- (void)dealloc { + [navigationController release]; + [window release]; + [super dealloc]; +} + + +@end + diff --git a/Classes/Example/example.pdf b/Classes/Example/example.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4da5f9312972900c3a6e29c48e8ec41b9fab8f74 GIT binary patch literal 73705 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 +#import "OARequestParameter.h" +#import "NSURL+Base.h" + + +@interface NSMutableURLRequest (OAParameterAdditions) + +- (NSArray *)parameters; +- (void)setParameters:(NSArray *)parameters; + +@end diff --git a/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.m b/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.m new file mode 100755 index 00000000..24035ed8 --- /dev/null +++ b/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.m @@ -0,0 +1,97 @@ +// +// NSMutableURLRequest+Parameters.m +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSMutableURLRequest+Parameters.h" + + +@implementation NSMutableURLRequest (OAParameterAdditions) + +- (NSArray *)parameters +{ + NSString *encodedParameters; + BOOL shouldfree = NO; + + if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) + encodedParameters = [[self URL] query]; + else + { + // POST, PUT + shouldfree = YES; + encodedParameters = [[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding]; + } + + if ((encodedParameters == nil) || ([encodedParameters isEqualToString:@""])) + { + if (shouldfree) + [encodedParameters release]; + + return nil; + } + + NSArray *encodedParameterPairs = [encodedParameters componentsSeparatedByString:@"&"]; + NSMutableArray *requestParameters = [[[NSMutableArray alloc] initWithCapacity:16] autorelease]; + + for (NSString *encodedPair in encodedParameterPairs) + { + NSArray *encodedPairElements = [encodedPair componentsSeparatedByString:@"="]; + OARequestParameter *parameter = [OARequestParameter requestParameterWithName:[[encodedPairElements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] + value:[[encodedPairElements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + [requestParameters addObject:parameter]; + } + + // Cleanup + if (shouldfree) + [encodedParameters release]; + + return requestParameters; +} + +- (void)setParameters:(NSArray *)parameters +{ + NSMutableString *encodedParameterPairs = [NSMutableString stringWithCapacity:256]; + + int position = 1; + for (OARequestParameter *requestParameter in parameters) + { + [encodedParameterPairs appendString:[requestParameter URLEncodedNameValuePair]]; + if (position < [parameters count]) + [encodedParameterPairs appendString:@"&"]; + + position++; + } + + if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", [[self URL] URLStringWithoutQuery], encodedParameterPairs]]]; + else + { + // POST, PUT + NSData *postData = [encodedParameterPairs dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + [self setHTTPBody:postData]; + [self setValue:[NSString stringWithFormat:@"%d", [postData length]] forHTTPHeaderField:@"Content-Length"]; + [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + } +} + +@end diff --git a/Classes/OAuth/Categories/NSString+URLEncoding.h b/Classes/OAuth/Categories/NSString+URLEncoding.h new file mode 100755 index 00000000..de06fe77 --- /dev/null +++ b/Classes/OAuth/Categories/NSString+URLEncoding.h @@ -0,0 +1,34 @@ +// +// NSString+URLEncoding.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface NSString (OAURLEncodingAdditions) + +- (NSString *)URLEncodedString; +- (NSString *)URLDecodedString; + +@end diff --git a/Classes/OAuth/Categories/NSString+URLEncoding.m b/Classes/OAuth/Categories/NSString+URLEncoding.m new file mode 100755 index 00000000..540492de --- /dev/null +++ b/Classes/OAuth/Categories/NSString+URLEncoding.m @@ -0,0 +1,52 @@ +// +// NSString+URLEncoding.m +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSString+URLEncoding.h" + + +@implementation NSString (OAURLEncodingAdditions) + +- (NSString *)URLEncodedString +{ + NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)self, + NULL, + CFSTR("!*'();:@&=+$,/?%#[]"), + kCFStringEncodingUTF8); + [result autorelease]; + return result; +} + +- (NSString*)URLDecodedString +{ + NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, + (CFStringRef)self, + CFSTR(""), + kCFStringEncodingUTF8); + [result autorelease]; + return result; +} + +@end diff --git a/Classes/OAuth/Categories/NSURL+Base.h b/Classes/OAuth/Categories/NSURL+Base.h new file mode 100755 index 00000000..5d12b696 --- /dev/null +++ b/Classes/OAuth/Categories/NSURL+Base.h @@ -0,0 +1,34 @@ +// +// NSURL+Base.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface NSURL (OABaseAdditions) + +- (NSString *)URLStringWithoutQuery; + +@end diff --git a/Classes/OAuth/Categories/NSURL+Base.m b/Classes/OAuth/Categories/NSURL+Base.m new file mode 100755 index 00000000..8d4d4209 --- /dev/null +++ b/Classes/OAuth/Categories/NSURL+Base.m @@ -0,0 +1,38 @@ +// +// NSURL+Base.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSURL+Base.h" + + +@implementation NSURL (OABaseAdditions) + +- (NSString *)URLStringWithoutQuery +{ + NSArray *parts = [[self absoluteString] componentsSeparatedByString:@"?"]; + return [parts objectAtIndex:0]; +} + +@end diff --git a/Classes/OAuth/Crytpo/Base64Transcoder.c b/Classes/OAuth/Crytpo/Base64Transcoder.c new file mode 100755 index 00000000..a655581e --- /dev/null +++ b/Classes/OAuth/Crytpo/Base64Transcoder.c @@ -0,0 +1,230 @@ +/* + * Base64Transcoder.c + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Base64Transcoder.h" + +#include +#include + +const u_int8_t kBase64EncodeTable[64] = { + /* 0 */ 'A', /* 1 */ 'B', /* 2 */ 'C', /* 3 */ 'D', + /* 4 */ 'E', /* 5 */ 'F', /* 6 */ 'G', /* 7 */ 'H', + /* 8 */ 'I', /* 9 */ 'J', /* 10 */ 'K', /* 11 */ 'L', + /* 12 */ 'M', /* 13 */ 'N', /* 14 */ 'O', /* 15 */ 'P', + /* 16 */ 'Q', /* 17 */ 'R', /* 18 */ 'S', /* 19 */ 'T', + /* 20 */ 'U', /* 21 */ 'V', /* 22 */ 'W', /* 23 */ 'X', + /* 24 */ 'Y', /* 25 */ 'Z', /* 26 */ 'a', /* 27 */ 'b', + /* 28 */ 'c', /* 29 */ 'd', /* 30 */ 'e', /* 31 */ 'f', + /* 32 */ 'g', /* 33 */ 'h', /* 34 */ 'i', /* 35 */ 'j', + /* 36 */ 'k', /* 37 */ 'l', /* 38 */ 'm', /* 39 */ 'n', + /* 40 */ 'o', /* 41 */ 'p', /* 42 */ 'q', /* 43 */ 'r', + /* 44 */ 's', /* 45 */ 't', /* 46 */ 'u', /* 47 */ 'v', + /* 48 */ 'w', /* 49 */ 'x', /* 50 */ 'y', /* 51 */ 'z', + /* 52 */ '0', /* 53 */ '1', /* 54 */ '2', /* 55 */ '3', + /* 56 */ '4', /* 57 */ '5', /* 58 */ '6', /* 59 */ '7', + /* 60 */ '8', /* 61 */ '9', /* 62 */ '+', /* 63 */ '/' +}; + +/* +-1 = Base64 end of data marker. +-2 = White space (tabs, cr, lf, space) +-3 = Noise (all non whitespace, non-base64 characters) +-4 = Dangerous noise +-5 = Illegal noise (null byte) +*/ + +const int8_t kBase64DecodeTable[128] = { + /* 0x00 */ -5, /* 0x01 */ -3, /* 0x02 */ -3, /* 0x03 */ -3, + /* 0x04 */ -3, /* 0x05 */ -3, /* 0x06 */ -3, /* 0x07 */ -3, + /* 0x08 */ -3, /* 0x09 */ -2, /* 0x0a */ -2, /* 0x0b */ -2, + /* 0x0c */ -2, /* 0x0d */ -2, /* 0x0e */ -3, /* 0x0f */ -3, + /* 0x10 */ -3, /* 0x11 */ -3, /* 0x12 */ -3, /* 0x13 */ -3, + /* 0x14 */ -3, /* 0x15 */ -3, /* 0x16 */ -3, /* 0x17 */ -3, + /* 0x18 */ -3, /* 0x19 */ -3, /* 0x1a */ -3, /* 0x1b */ -3, + /* 0x1c */ -3, /* 0x1d */ -3, /* 0x1e */ -3, /* 0x1f */ -3, + /* ' ' */ -2, /* '!' */ -3, /* '"' */ -3, /* '#' */ -3, + /* '$' */ -3, /* '%' */ -3, /* '&' */ -3, /* ''' */ -3, + /* '(' */ -3, /* ')' */ -3, /* '*' */ -3, /* '+' */ 62, + /* ',' */ -3, /* '-' */ -3, /* '.' */ -3, /* '/' */ 63, + /* '0' */ 52, /* '1' */ 53, /* '2' */ 54, /* '3' */ 55, + /* '4' */ 56, /* '5' */ 57, /* '6' */ 58, /* '7' */ 59, + /* '8' */ 60, /* '9' */ 61, /* ':' */ -3, /* ';' */ -3, + /* '<' */ -3, /* '=' */ -1, /* '>' */ -3, /* '?' */ -3, + /* '@' */ -3, /* 'A' */ 0, /* 'B' */ 1, /* 'C' */ 2, + /* 'D' */ 3, /* 'E' */ 4, /* 'F' */ 5, /* 'G' */ 6, + /* 'H' */ 7, /* 'I' */ 8, /* 'J' */ 9, /* 'K' */ 10, + /* 'L' */ 11, /* 'M' */ 12, /* 'N' */ 13, /* 'O' */ 14, + /* 'P' */ 15, /* 'Q' */ 16, /* 'R' */ 17, /* 'S' */ 18, + /* 'T' */ 19, /* 'U' */ 20, /* 'V' */ 21, /* 'W' */ 22, + /* 'X' */ 23, /* 'Y' */ 24, /* 'Z' */ 25, /* '[' */ -3, + /* '\' */ -3, /* ']' */ -3, /* '^' */ -3, /* '_' */ -3, + /* '`' */ -3, /* 'a' */ 26, /* 'b' */ 27, /* 'c' */ 28, + /* 'd' */ 29, /* 'e' */ 30, /* 'f' */ 31, /* 'g' */ 32, + /* 'h' */ 33, /* 'i' */ 34, /* 'j' */ 35, /* 'k' */ 36, + /* 'l' */ 37, /* 'm' */ 38, /* 'n' */ 39, /* 'o' */ 40, + /* 'p' */ 41, /* 'q' */ 42, /* 'r' */ 43, /* 's' */ 44, + /* 't' */ 45, /* 'u' */ 46, /* 'v' */ 47, /* 'w' */ 48, + /* 'x' */ 49, /* 'y' */ 50, /* 'z' */ 51, /* '{' */ -3, + /* '|' */ -3, /* '}' */ -3, /* '~' */ -3, /* 0x7f */ -3 +}; + +const u_int8_t kBits_00000011 = 0x03; +const u_int8_t kBits_00001111 = 0x0F; +const u_int8_t kBits_00110000 = 0x30; +const u_int8_t kBits_00111100 = 0x3C; +const u_int8_t kBits_00111111 = 0x3F; +const u_int8_t kBits_11000000 = 0xC0; +const u_int8_t kBits_11110000 = 0xF0; +const u_int8_t kBits_11111100 = 0xFC; + +size_t EstimateBas64EncodedDataSize(size_t inDataSize) +{ +size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4; +theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72; +return(theEncodedDataSize); +} + +size_t EstimateBas64DecodedDataSize(size_t inDataSize) +{ +size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3; +//theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72; +return(theDecodedDataSize); +} + +bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize) +{ +size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize); +if (*ioOutputDataSize < theEncodedDataSize) + return(false); +*ioOutputDataSize = theEncodedDataSize; +const u_int8_t *theInPtr = (const u_int8_t *)inInputData; +u_int32_t theInIndex = 0, theOutIndex = 0; +for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0]; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +const size_t theRemainingBytes = inInputDataSize - theInIndex; +if (theRemainingBytes == 1) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = '='; + outOutputData[theOutIndex++] = '='; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +else if (theRemainingBytes == 2) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6]; + outOutputData[theOutIndex++] = '='; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +return(true); +} + +bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize) +{ +memset(ioOutputData, '.', *ioOutputDataSize); + +size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize); +if (*ioOutputDataSize < theDecodedDataSize) + return(false); +*ioOutputDataSize = 0; +const u_int8_t *theInPtr = (const u_int8_t *)inInputData; +u_int8_t *theOutPtr = (u_int8_t *)ioOutputData; +size_t theInIndex = 0, theOutIndex = 0; +u_int8_t theOutputOctet; +size_t theSequence = 0; +for (; theInIndex < inInputDataSize; ) + { + int8_t theSextet = 0; + + int8_t theCurrentInputOctet = theInPtr[theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + if (theSextet == -1) + break; + while (theSextet == -2) + { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + } + while (theSextet == -3) + { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + } + if (theSequence == 0) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100; + } + else if (theSequence == 1) + { + theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011; + theOutPtr[theOutIndex++] = theOutputOctet; + } + else if (theSequence == 2) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000; + } + else if (theSequence == 3) + { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111; + theOutPtr[theOutIndex++] = theOutputOctet; + } + else if (theSequence == 4) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000; + } + else if (theSequence == 5) + { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111; + theOutPtr[theOutIndex++] = theOutputOctet; + } + theSequence = (theSequence + 1) % 6; + if (theSequence != 2 && theSequence != 4) + theInIndex++; + } +*ioOutputDataSize = theOutIndex; +return(true); +} diff --git a/Classes/OAuth/Crytpo/Base64Transcoder.h b/Classes/OAuth/Crytpo/Base64Transcoder.h new file mode 100755 index 00000000..87520989 --- /dev/null +++ b/Classes/OAuth/Crytpo/Base64Transcoder.h @@ -0,0 +1,36 @@ +/* + * Base64Transcoder.h + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +extern size_t EstimateBas64EncodedDataSize(size_t inDataSize); +extern size_t EstimateBas64DecodedDataSize(size_t inDataSize); + +extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize); +extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize); + diff --git a/Classes/OAuth/Crytpo/hmac.c b/Classes/OAuth/Crytpo/hmac.c new file mode 100755 index 00000000..eea9a707 --- /dev/null +++ b/Classes/OAuth/Crytpo/hmac.c @@ -0,0 +1,86 @@ +// +// hmac.c +// OAuthConsumer +// +// Created by Jonathan Wight on 4/8/8. +// Copyright 2008 Jonathan Wight. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * Implementation of HMAC-SHA1. Adapted from example at http://tools.ietf.org/html/rfc2104 + + */ + +#include "sha1.h" + +#include +#include + +void hmac_sha1(const unsigned char *inText, size_t inTextLength, unsigned char* inKey, size_t inKeyLength, unsigned char *outDigest) +{ +const size_t B = 64; +const size_t L = 20; + +SHA1_CTX theSHA1Context; +unsigned char k_ipad[B + 1]; /* inner padding - key XORd with ipad */ +unsigned char k_opad[B + 1]; /* outer padding - key XORd with opad */ + +/* if key is longer than 64 bytes reset it to key=SHA1 (key) */ +if (inKeyLength > B) + { + SHA1Init(&theSHA1Context); + SHA1Update(&theSHA1Context, inKey, inKeyLength); + SHA1Final(inKey, &theSHA1Context); + inKeyLength = L; + } + +/* start out by storing key in pads */ +memset(k_ipad, 0, sizeof k_ipad); +memset(k_opad, 0, sizeof k_opad); +memcpy(k_ipad, inKey, inKeyLength); +memcpy(k_opad, inKey, inKeyLength); + +/* XOR key with ipad and opad values */ +int i; +for (i = 0; i < B; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + +/* +* perform inner SHA1 +*/ +SHA1Init(&theSHA1Context); /* init context for 1st pass */ +SHA1Update(&theSHA1Context, k_ipad, B); /* start with inner pad */ +SHA1Update(&theSHA1Context, (unsigned char *)inText, inTextLength); /* then text of datagram */ +SHA1Final((unsigned char *)outDigest, &theSHA1Context); /* finish up 1st pass */ + +/* +* perform outer SHA1 +*/ +SHA1Init(&theSHA1Context); /* init context for 2nd +* pass */ +SHA1Update(&theSHA1Context, k_opad, B); /* start with outer pad */ +SHA1Update(&theSHA1Context, outDigest, L); /* then results of 1st +* hash */ +SHA1Final(outDigest, &theSHA1Context); /* finish up 2nd pass */ + +} \ No newline at end of file diff --git a/Classes/OAuth/Crytpo/hmac.h b/Classes/OAuth/Crytpo/hmac.h new file mode 100755 index 00000000..51eca9f6 --- /dev/null +++ b/Classes/OAuth/Crytpo/hmac.h @@ -0,0 +1,31 @@ +// +// hmac.h +// OAuthConsumer +// +// Created by Jonathan Wight on 4/8/8. +// Copyright 2008 Jonathan Wight. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef HMAC_H +#define HMAC_H 1 + +extern void hmac_sha1(const unsigned char *inText, int inTextLength, unsigned char* inKey, const unsigned int inKeyLength, unsigned char *outDigest); + +#endif /* HMAC_H */ \ No newline at end of file diff --git a/Classes/OAuth/Crytpo/sha1.c b/Classes/OAuth/Crytpo/sha1.c new file mode 100755 index 00000000..16f5dbcf --- /dev/null +++ b/Classes/OAuth/Crytpo/sha1.c @@ -0,0 +1,169 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd if true. */ +#if __LITTLE_ENDIAN__ +#define LITTLE_ENDIAN +#endif +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#include +#include + +#include "sha1.h" + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifdef LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) +{ +unsigned long a, b, c, d, e; +typedef union { + unsigned char c[64]; + unsigned long l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) +{ +unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +unsigned long i, j; +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} diff --git a/Classes/OAuth/Crytpo/sha1.h b/Classes/OAuth/Crytpo/sha1.h new file mode 100755 index 00000000..f3218ee5 --- /dev/null +++ b/Classes/OAuth/Crytpo/sha1.h @@ -0,0 +1,12 @@ + +// From http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/sha1.c + +typedef struct { + unsigned long state[5]; + unsigned long count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +extern void SHA1Init(SHA1_CTX* context); +extern void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); +extern void SHA1Final(unsigned char digest[20], SHA1_CTX* context); diff --git a/Classes/OAuth/OAAsynchronousDataFetcher.h b/Classes/OAuth/OAAsynchronousDataFetcher.h new file mode 100644 index 00000000..20a23152 --- /dev/null +++ b/Classes/OAuth/OAAsynchronousDataFetcher.h @@ -0,0 +1,45 @@ +// +// OAAsynchronousDataFetcher.h +// OAuthConsumer +// +// Created by Zsombor Szabó on 12/3/08. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import "OAMutableURLRequest.h" + +@interface OAAsynchronousDataFetcher : NSObject { + OAMutableURLRequest *request; + NSHTTPURLResponse *response; + NSURLConnection *connection; + NSMutableData *responseData; + id delegate; + SEL didFinishSelector; + SEL didFailSelector; +} + ++ (id)asynchronousFetcherWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; +- (id)initWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; + +- (void)start; +- (void)cancel; + +@end diff --git a/Classes/OAuth/OAAsynchronousDataFetcher.m b/Classes/OAuth/OAAsynchronousDataFetcher.m new file mode 100644 index 00000000..58472bc8 --- /dev/null +++ b/Classes/OAuth/OAAsynchronousDataFetcher.m @@ -0,0 +1,134 @@ +// +// OAAsynchronousDataFetcher.m +// OAuthConsumer +// +// Created by Zsombor Szabó on 12/3/08. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "OAAsynchronousDataFetcher.h" + +#import "OAServiceTicket.h" + +@implementation OAAsynchronousDataFetcher + ++ (id)asynchronousFetcherWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector +{ + return [[[OAAsynchronousDataFetcher alloc] initWithRequest:aRequest delegate:aDelegate didFinishSelector:finishSelector didFailSelector:failSelector] autorelease]; +} + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector +{ + if (self = [super init]) + { + request = [aRequest retain]; + delegate = aDelegate; + didFinishSelector = finishSelector; + didFailSelector = failSelector; + } + return self; +} + +- (void)start +{ + [request prepare]; + + if (connection) + [connection release]; + + connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; + + if (connection) + { + if (responseData) + [responseData release]; + responseData = [[NSMutableData data] retain]; + } + else + { + OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request + response:nil + didSucceed:NO]; + [delegate performSelector:didFailSelector + withObject:ticket + withObject:nil]; + [ticket release]; + } +} + +- (void)cancel +{ + if (connection) + { + [connection cancel]; + [connection release]; + connection = nil; + } +} + +- (void)dealloc +{ + if (request) [request release]; + if (connection) [connection release]; + if (response) [response release]; + if (responseData) [responseData release]; + [super dealloc]; +} + +#pragma mark - +#pragma mark NSURLConnection methods + +- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)aResponse +{ + if (response) + [response release]; + response = [aResponse retain]; + [responseData setLength:0]; +} + +- (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)data +{ + [responseData appendData:data]; +} + +- (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error +{ + OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request + response:response + didSucceed:NO]; + [delegate performSelector:didFailSelector + withObject:ticket + withObject:error]; + + [ticket release]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection +{ + OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request + response:response + didSucceed:[(NSHTTPURLResponse *)response statusCode] < 400]; + [delegate performSelector:didFinishSelector + withObject:ticket + withObject:responseData]; + + [ticket release]; +} + +@end diff --git a/Classes/OAuth/OAConsumer.h b/Classes/OAuth/OAConsumer.h new file mode 100755 index 00000000..73bdab65 --- /dev/null +++ b/Classes/OAuth/OAConsumer.h @@ -0,0 +1,40 @@ +// +// OAConsumer.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface OAConsumer : NSObject { +@protected + NSString *key; + NSString *secret; +} +@property(retain) NSString *key; +@property(retain) NSString *secret; + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; + +@end diff --git a/Classes/OAuth/OAConsumer.m b/Classes/OAuth/OAConsumer.m new file mode 100755 index 00000000..0582ad9d --- /dev/null +++ b/Classes/OAuth/OAConsumer.m @@ -0,0 +1,51 @@ +// +// OAConsumer.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "OAConsumer.h" + + +@implementation OAConsumer +@synthesize key, secret; + +#pragma mark init + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret +{ + if (self = [super init]) + { + self.key = aKey; + self.secret = aSecret; + } + return self; +} + +- (void)dealloc +{ + [key release]; + [secret release]; + [super dealloc]; +} + +@end diff --git a/Classes/OAuth/OADataFetcher.h b/Classes/OAuth/OADataFetcher.h new file mode 100755 index 00000000..74273e37 --- /dev/null +++ b/Classes/OAuth/OADataFetcher.h @@ -0,0 +1,45 @@ +// +// OADataFetcher.h +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "OAMutableURLRequest.h" +#import "OAServiceTicket.h" + + +@interface OADataFetcher : NSObject { +@private + OAMutableURLRequest *request; + NSHTTPURLResponse *response; + NSURLConnection *connection; + NSError *error; + NSData *responseData; + id delegate; + SEL didFinishSelector; + SEL didFailSelector; +} + +- (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; + +@end diff --git a/Classes/OAuth/OADataFetcher.m b/Classes/OAuth/OADataFetcher.m new file mode 100755 index 00000000..b9c6d67c --- /dev/null +++ b/Classes/OAuth/OADataFetcher.m @@ -0,0 +1,65 @@ +// +// OADataFetcher.m +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OADataFetcher.h" + + +@implementation OADataFetcher + +- (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest + delegate:(id)aDelegate + didFinishSelector:(SEL)finishSelector + didFailSelector:(SEL)failSelector +{ + request = aRequest; + delegate = aDelegate; + didFinishSelector = finishSelector; + didFailSelector = failSelector; + + [request prepare]; + + responseData = [NSURLConnection sendSynchronousRequest:request + returningResponse:&response + error:&error]; + + if (response == nil || responseData == nil || error != nil) { + OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request + response:response + didSucceed:NO]; + [delegate performSelector:didFailSelector + withObject:ticket + withObject:error]; + } else { + OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request + response:response + didSucceed:[(NSHTTPURLResponse *)response statusCode] < 400]; + [delegate performSelector:didFinishSelector + withObject:ticket + withObject:responseData]; + } +} + +@end diff --git a/Classes/OAuth/OAHMAC_SHA1SignatureProvider.h b/Classes/OAuth/OAHMAC_SHA1SignatureProvider.h new file mode 100755 index 00000000..d259c4ea --- /dev/null +++ b/Classes/OAuth/OAHMAC_SHA1SignatureProvider.h @@ -0,0 +1,32 @@ +// +// OAHMAC_SHA1SignatureProvider.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OASignatureProviding.h" + + +@interface OAHMAC_SHA1SignatureProvider : NSObject +@end diff --git a/Classes/OAuth/OAHMAC_SHA1SignatureProvider.m b/Classes/OAuth/OAHMAC_SHA1SignatureProvider.m new file mode 100755 index 00000000..432baf7a --- /dev/null +++ b/Classes/OAuth/OAHMAC_SHA1SignatureProvider.m @@ -0,0 +1,58 @@ +// +// OAHMAC_SHA1SignatureProvider.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAHMAC_SHA1SignatureProvider.h" +#import + +#include "Base64Transcoder.h" + +@implementation OAHMAC_SHA1SignatureProvider + +- (NSString *)name +{ + return @"HMAC-SHA1"; +} + +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret +{ + NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding]; + NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding]; + unsigned char result[20]; + CCHmac(kCCHmacAlgSHA1, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], result); + + //Base64 Encoding + + char base64Result[32]; + size_t theResultLength = 32; + Base64EncodeData(result, 20, base64Result, &theResultLength); + NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength]; + + NSString *base64EncodedResult = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding]; + + return [base64EncodedResult autorelease]; +} + +@end diff --git a/Classes/OAuth/OAMutableURLRequest.h b/Classes/OAuth/OAMutableURLRequest.h new file mode 100755 index 00000000..fdf0a1a8 --- /dev/null +++ b/Classes/OAuth/OAMutableURLRequest.h @@ -0,0 +1,68 @@ +// +// OAMutableURLRequest.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OAConsumer.h" +#import "OAToken.h" +#import "OAHMAC_SHA1SignatureProvider.h" +#import "OASignatureProviding.h" +#import "NSMutableURLRequest+Parameters.h" +#import "NSURL+Base.h" + + +@interface OAMutableURLRequest : NSMutableURLRequest { +@protected + OAConsumer *consumer; + OAToken *token; + NSString *realm; + NSString *signature; + id signatureProvider; + NSString *nonce; + NSString *timestamp; + NSMutableDictionary *extraOAuthParameters; +} +@property(readonly) NSString *signature; +@property(readonly) NSString *nonce; + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider; + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider + nonce:(NSString *)aNonce + timestamp:(NSString *)aTimestamp; + +- (void)prepare; + +- (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)parameterValue; + +@end diff --git a/Classes/OAuth/OAMutableURLRequest.m b/Classes/OAuth/OAMutableURLRequest.m new file mode 100755 index 00000000..d32f759a --- /dev/null +++ b/Classes/OAuth/OAMutableURLRequest.m @@ -0,0 +1,231 @@ +// +// OAMutableURLRequest.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAMutableURLRequest.h" + + +@interface OAMutableURLRequest (Private) +- (void)_generateTimestamp; +- (void)_generateNonce; +- (NSString *)_signatureBaseString; +@end + +@implementation OAMutableURLRequest +@synthesize signature, nonce; + +#pragma mark init + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider +{ + if (self = [super initWithURL:aUrl + cachePolicy:NSURLRequestReloadIgnoringCacheData + timeoutInterval:10.0]) + { + consumer = [aConsumer retain]; + + // empty token for Unauthorized Request Token transaction + if (aToken == nil) + token = [[OAToken alloc] init]; + else + token = [aToken retain]; + + if (aRealm == nil) + realm = [[NSString alloc] initWithString:@""]; + else + realm = [aRealm retain]; + + // default to HMAC-SHA1 + if (aProvider == nil) + signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; + else + signatureProvider = [aProvider retain]; + + [self _generateTimestamp]; + [self _generateNonce]; + } + return self; +} + +// Setting a timestamp and nonce to known +// values can be helpful for testing +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider + nonce:(NSString *)aNonce + timestamp:(NSString *)aTimestamp +{ + if (self = [super initWithURL:aUrl + cachePolicy:NSURLRequestReloadIgnoringCacheData + timeoutInterval:10.0]) + { + consumer = [aConsumer retain]; + + // empty token for Unauthorized Request Token transaction + if (aToken == nil) + token = [[OAToken alloc] init]; + else + token = [aToken retain]; + + if (aRealm == nil) + realm = [[NSString alloc] initWithString:@""]; + else + realm = [aRealm retain]; + + // default to HMAC-SHA1 + if (aProvider == nil) + signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; + else + signatureProvider = [aProvider retain]; + + timestamp = [aTimestamp retain]; + nonce = [aNonce retain]; + } + return self; +} + +- (void)dealloc +{ + [consumer release]; + [token release]; + [realm release]; + [signatureProvider release]; + [timestamp release]; + [nonce release]; + [extraOAuthParameters release]; + [super dealloc]; +} + +#pragma mark - +#pragma mark Public + +- (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)parameterValue +{ + assert(parameterName && parameterValue); + + if (extraOAuthParameters == nil) { + extraOAuthParameters = [NSMutableDictionary new]; + } + + [extraOAuthParameters setObject:parameterValue forKey:parameterName]; +} + +- (void)prepare +{ + // sign + // Secrets must be urlencoded before concatenated with '&' + // TODO: if later RSA-SHA1 support is added then a little code redesign is needed + signature = [signatureProvider signClearText:[self _signatureBaseString] + withSecret:[NSString stringWithFormat:@"%@&%@", + [consumer.secret URLEncodedString], + [token.secret URLEncodedString]]]; + + // set OAuth headers + NSString *oauthToken; + if ([token.key isEqualToString:@""]) + oauthToken = @""; // not used on Request Token transactions + else + oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", ", [token.key URLEncodedString]]; + + NSMutableString *extraParameters = [NSMutableString string]; + + // Adding the optional parameters in sorted order isn't required by the OAuth spec, but it makes it possible to hard-code expected values in the unit tests. + for(NSString *parameterName in [[extraOAuthParameters allKeys] sortedArrayUsingSelector:@selector(compare:)]) + { + [extraParameters appendFormat:@", %@=\"%@\"", + [parameterName URLEncodedString], + [[extraOAuthParameters objectForKey:parameterName] URLEncodedString]]; + } + + NSString *oauthHeader = [NSString stringWithFormat:@"OAuth realm=\"%@\", oauth_consumer_key=\"%@\", %@oauth_signature_method=\"%@\", oauth_signature=\"%@\", oauth_timestamp=\"%@\", oauth_nonce=\"%@\", oauth_version=\"1.0\"%@", + [realm URLEncodedString], + [consumer.key URLEncodedString], + oauthToken, + [[signatureProvider name] URLEncodedString], + [signature URLEncodedString], + timestamp, + nonce, + extraParameters]; + + [self setValue:oauthHeader forHTTPHeaderField:@"Authorization"]; +} + +#pragma mark - +#pragma mark Private + +- (void)_generateTimestamp +{ + timestamp = [[NSString stringWithFormat:@"%d", time(NULL)] retain]; +} + +- (void)_generateNonce +{ + CFUUIDRef theUUID = CFUUIDCreate(NULL); + CFStringRef string = CFUUIDCreateString(NULL, theUUID); + NSMakeCollectable(theUUID); + nonce = (NSString *)string; +} + +- (NSString *)_signatureBaseString +{ + // OAuth Spec, Section 9.1.1 "Normalize Request Parameters" + // build a sorted array of both request parameters and OAuth header parameters + NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:(6 + [[self parameters] count])]; // 6 being the number of OAuth params in the Signature Base String + + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_consumer_key" value:consumer.key] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_signature_method" value:[signatureProvider name]] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_timestamp" value:timestamp] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_nonce" value:nonce] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_version" value:@"1.0"] URLEncodedNameValuePair]]; + + if (![token.key isEqualToString:@""]) { + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_token" value:token.key] URLEncodedNameValuePair]]; + } + + for (OARequestParameter *param in [self parameters]) { + [parameterPairs addObject:[param URLEncodedNameValuePair]]; + } + + NSArray *sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)]; + NSString *normalizedRequestParameters = [sortedPairs componentsJoinedByString:@"&"]; + + // OAuth Spec, Section 9.1.2 "Concatenate Request Elements" + NSString *ret = [NSString stringWithFormat:@"%@&%@&%@", + [self HTTPMethod], + [[[self URL] URLStringWithoutQuery] URLEncodedString], + [normalizedRequestParameters URLEncodedString]]; + + //NSLog(@"ret %@", ret); + + return ret; +} + +@end diff --git a/Classes/OAuth/OAPlaintextSignatureProvider.h b/Classes/OAuth/OAPlaintextSignatureProvider.h new file mode 100755 index 00000000..96bb2f28 --- /dev/null +++ b/Classes/OAuth/OAPlaintextSignatureProvider.h @@ -0,0 +1,31 @@ +// +// OAPlaintextSignatureProvider.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OASignatureProviding.h" + +@interface OAPlaintextSignatureProvider : NSObject +@end diff --git a/Classes/OAuth/OAPlaintextSignatureProvider.m b/Classes/OAuth/OAPlaintextSignatureProvider.m new file mode 100755 index 00000000..6f0c1c3a --- /dev/null +++ b/Classes/OAuth/OAPlaintextSignatureProvider.m @@ -0,0 +1,43 @@ +// +// OAPlaintextSignatureProvider.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAPlaintextSignatureProvider.h" +#import "NSString+URLEncoding.h" + + +@implementation OAPlaintextSignatureProvider + +- (NSString *)name +{ + return @"PLAINTEXT"; +} + +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret +{ + return secret; +} + +@end diff --git a/Classes/OAuth/OAProblem.h b/Classes/OAuth/OAProblem.h new file mode 100755 index 00000000..fe64c700 --- /dev/null +++ b/Classes/OAuth/OAProblem.h @@ -0,0 +1,53 @@ +// +// OAProblem.h +// OAuthConsumer +// +// Created by Alberto García Hierro on 03/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import + +enum { + kOAProblemSignatureMethodRejected = 0, + kOAProblemParameterAbsent, + kOAProblemVersionRejected, + kOAProblemConsumerKeyUnknown, + kOAProblemTokenRejected, + kOAProblemSignatureInvalid, + kOAProblemNonceUsed, + kOAProblemTimestampRefused, + kOAProblemTokenExpired, + kOAProblemTokenNotRenewable +}; + +@interface OAProblem : NSObject { + const NSString *problem; +} + +@property (readonly) const NSString *problem; + +- (id)initWithProblem:(const NSString *)aProblem; +- (id)initWithResponseBody:(const NSString *)response; + +- (BOOL)isEqualToProblem:(OAProblem *)aProblem; +- (BOOL)isEqualToString:(const NSString *)aProblem; +- (BOOL)isEqualTo:(id)aProblem; +- (int)code; + ++ (OAProblem *)problemWithResponseBody:(const NSString *)response; + ++ (const NSArray *)validProblems; + ++ (OAProblem *)SignatureMethodRejected; ++ (OAProblem *)ParameterAbsent; ++ (OAProblem *)VersionRejected; ++ (OAProblem *)ConsumerKeyUnknown; ++ (OAProblem *)TokenRejected; ++ (OAProblem *)SignatureInvalid; ++ (OAProblem *)NonceUsed; ++ (OAProblem *)TimestampRefused; ++ (OAProblem *)TokenExpired; ++ (OAProblem *)TokenNotRenewable; + +@end diff --git a/Classes/OAuth/OAProblem.m b/Classes/OAuth/OAProblem.m new file mode 100755 index 00000000..7a885a3c --- /dev/null +++ b/Classes/OAuth/OAProblem.m @@ -0,0 +1,165 @@ +// +// OAProblem.m +// OAuthConsumer +// +// Created by Alberto García Hierro on 03/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import "OAProblem.h" + +const NSString *signature_method_rejected = @"signature_method_rejected"; +const NSString *parameter_absent = @"parameter_absent"; +const NSString *version_rejected = @"version_rejected"; +const NSString *consumer_key_unknown = @"consumer_key_unknown"; +const NSString *token_rejected = @"token_rejected"; +const NSString *signature_invalid = @"signature_invalid"; +const NSString *nonce_used = @"nonce_used"; +const NSString *timestamp_refused = @"timestamp_refused"; +const NSString *token_expired = @"token_expired"; +const NSString *token_not_renewable = @"token_not_renewable"; + +@implementation OAProblem + +@synthesize problem; + +- (id)initWithPointer:(const NSString *) aPointer +{ + [super init]; + problem = aPointer; + return self; +} + +- (id)initWithProblem:(const NSString *) aProblem +{ + NSUInteger idx = [[OAProblem validProblems] indexOfObject:aProblem]; + if (idx == NSNotFound) { + return nil; + } + + return [self initWithPointer: [[OAProblem validProblems] objectAtIndex:idx]]; +} + +- (id)initWithResponseBody:(const NSString *) response +{ + NSArray *fields = [response componentsSeparatedByString:@"&"]; + for (NSString *field in fields) { + if ([field hasPrefix:@"oauth_problem="]) { + NSString *value = [[field componentsSeparatedByString:@"="] objectAtIndex:1]; + return [self initWithProblem:value]; + } + } + + return nil; +} + ++ (OAProblem *)problemWithResponseBody:(const NSString *) response +{ + return [[[OAProblem alloc] initWithResponseBody:response] autorelease]; +} + ++ (const NSArray *)validProblems +{ + static NSArray *array; + if (!array) { + array = [[NSArray alloc] initWithObjects:signature_method_rejected, + parameter_absent, + version_rejected, + consumer_key_unknown, + token_rejected, + signature_invalid, + nonce_used, + timestamp_refused, + token_expired, + token_not_renewable, + nil]; + } + + return array; +} + +- (BOOL)isEqualToProblem:(OAProblem *) aProblem +{ + return [problem isEqualToString:(NSString *)aProblem->problem]; +} + +- (BOOL)isEqualToString:(const NSString *) aProblem +{ + return [problem isEqualToString:(NSString *)aProblem]; +} + +- (BOOL)isEqualTo:(id) aProblem +{ + if ([aProblem isKindOfClass:[NSString class]]) { + return [self isEqualToString:aProblem]; + } + + if ([aProblem isKindOfClass:[OAProblem class]]) { + return [self isEqualToProblem:aProblem]; + } + + return NO; +} + +- (int)code { + return [[[self class] validProblems] indexOfObject:problem]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"OAuth Problem: %@", (NSString *)problem]; +} + +#pragma mark class_methods + ++ (OAProblem *)SignatureMethodRejected +{ + return [[[OAProblem alloc] initWithPointer:signature_method_rejected] autorelease]; +} + ++ (OAProblem *)ParameterAbsent +{ + return [[[OAProblem alloc] initWithPointer:parameter_absent] autorelease]; +} + ++ (OAProblem *)VersionRejected +{ + return [[[OAProblem alloc] initWithPointer:version_rejected] autorelease]; +} + ++ (OAProblem *)ConsumerKeyUnknown +{ + return [[[OAProblem alloc] initWithPointer:consumer_key_unknown] autorelease]; +} + ++ (OAProblem *)TokenRejected +{ + return [[[OAProblem alloc] initWithPointer:token_rejected] autorelease]; +} + ++ (OAProblem *)SignatureInvalid +{ + return [[[OAProblem alloc] initWithPointer:signature_invalid] autorelease]; +} + ++ (OAProblem *)NonceUsed +{ + return [[[OAProblem alloc] initWithPointer:nonce_used] autorelease]; +} + ++ (OAProblem *)TimestampRefused +{ + return [[[OAProblem alloc] initWithPointer:timestamp_refused] autorelease]; +} + ++ (OAProblem *)TokenExpired +{ + return [[[OAProblem alloc] initWithPointer:token_expired] autorelease]; +} + ++ (OAProblem *)TokenNotRenewable +{ + return [[[OAProblem alloc] initWithPointer:token_not_renewable] autorelease]; +} + +@end diff --git a/Classes/OAuth/OARequestParameter.h b/Classes/OAuth/OARequestParameter.h new file mode 100755 index 00000000..03eee3e0 --- /dev/null +++ b/Classes/OAuth/OARequestParameter.h @@ -0,0 +1,45 @@ +// +// OARequestParameter.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "NSString+URLEncoding.h" + + +@interface OARequestParameter : NSObject { +@protected + NSString *name; + NSString *value; +} +@property(retain) NSString *name; +@property(retain) NSString *value; + ++ (id)requestParameterWithName:(NSString *)aName value:(NSString *)aValue; +- (id)initWithName:(NSString *)aName value:(NSString *)aValue; +- (NSString *)URLEncodedName; +- (NSString *)URLEncodedValue; +- (NSString *)URLEncodedNameValuePair; + +@end diff --git a/Classes/OAuth/OARequestParameter.m b/Classes/OAuth/OARequestParameter.m new file mode 100755 index 00000000..59b6a8a6 --- /dev/null +++ b/Classes/OAuth/OARequestParameter.m @@ -0,0 +1,70 @@ +// +// OARequestParameter.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OARequestParameter.h" + + +@implementation OARequestParameter +@synthesize name, value; + ++ (id)requestParameterWithName:(NSString *)aName value:(NSString *)aValue +{ + return [[[OARequestParameter alloc] initWithName:aName value:aValue] autorelease]; +} + +- (id)initWithName:(NSString *)aName value:(NSString *)aValue +{ + if (self = [super init]) + { + self.name = aName; + self.value = aValue; + } + return self; +} + +- (void)dealloc +{ + [name release]; + [value release]; + [super dealloc]; +} + +- (NSString *)URLEncodedName +{ + return [self.name URLEncodedString]; +} + +- (NSString *)URLEncodedValue +{ + return [self.value URLEncodedString]; +} + +- (NSString *)URLEncodedNameValuePair +{ + return [NSString stringWithFormat:@"%@=%@", [self URLEncodedName], [self URLEncodedValue]]; +} + +@end diff --git a/Classes/OAuth/OAServiceTicket.h b/Classes/OAuth/OAServiceTicket.h new file mode 100755 index 00000000..9a8eb348 --- /dev/null +++ b/Classes/OAuth/OAServiceTicket.h @@ -0,0 +1,47 @@ +// +// OAServiceTicket.h +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OAMutableURLRequest.h" + + +@interface OAServiceTicket : NSObject { +@private + OAMutableURLRequest *request; + NSHTTPURLResponse *response; + NSData *data; + BOOL didSucceed; +} +@property(readonly) OAMutableURLRequest *request; +@property(readonly) NSHTTPURLResponse *response; +@property(readonly) NSData *data; +@property(readonly) BOOL didSucceed; +@property(readonly) NSString *body; + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse didSucceed:(BOOL)success; +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success; + +@end diff --git a/Classes/OAuth/OAServiceTicket.m b/Classes/OAuth/OAServiceTicket.m new file mode 100755 index 00000000..fb6e3b7c --- /dev/null +++ b/Classes/OAuth/OAServiceTicket.m @@ -0,0 +1,56 @@ +// +// OAServiceTicket.m +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAServiceTicket.h" + + +@implementation OAServiceTicket +@synthesize request, response, data, didSucceed; + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse didSucceed:(BOOL)success +{ + return [self initWithRequest:aRequest response:aResponse data:nil didSucceed:success]; +} + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success { + [super init]; + request = aRequest; + response = aResponse; + data = aData; + didSucceed = success; + return self; +} + +- (NSString *)body +{ + if (!data) { + return nil; + } + + return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; +} + +@end diff --git a/Classes/OAuth/OASignatureProviding.h b/Classes/OAuth/OASignatureProviding.h new file mode 100755 index 00000000..0c7e4f8c --- /dev/null +++ b/Classes/OAuth/OASignatureProviding.h @@ -0,0 +1,34 @@ +// +// OASignatureProviding.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@protocol OASignatureProviding + +- (NSString *)name; +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret; + +@end diff --git a/Classes/OAuth/OAToken.h b/Classes/OAuth/OAToken.h new file mode 100755 index 00000000..8dd331e1 --- /dev/null +++ b/Classes/OAuth/OAToken.h @@ -0,0 +1,41 @@ +// +// OAToken.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@interface OAToken : NSObject { +@protected + NSString *key; + NSString *secret; +} +@property(retain) NSString *key; +@property(retain) NSString *secret; + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; +- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; +- (id)initWithHTTPResponseBody:(NSString *)body; +- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; + +@end diff --git a/Classes/OAuth/OAToken.m b/Classes/OAuth/OAToken.m new file mode 100755 index 00000000..d4f24911 --- /dev/null +++ b/Classes/OAuth/OAToken.m @@ -0,0 +1,105 @@ +// +// OAToken.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAToken.h" + + +@implementation OAToken + +@synthesize key, secret; + +#pragma mark init + +- (id)init +{ + if (self = [super init]) + { + self.key = @""; + self.secret = @""; + } + return self; +} + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret +{ + if (self = [super init]) + { + self.key = aKey; + self.secret = aSecret; + } + return self; +} + +- (id)initWithHTTPResponseBody:(NSString *)body +{ + if (self = [super init]) + { + NSArray *pairs = [body componentsSeparatedByString:@"&"]; + + for (NSString *pair in pairs) { + NSArray *elements = [pair componentsSeparatedByString:@"="]; + if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token"]) { + self.key = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_secret"]) { + self.secret = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } + } + } + return self; +} + +- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix +{ + if (self = [super init]) + { + NSString *theKey = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@"OAUTH_%@_%@_KEY", prefix, provider]]; + NSString *theSecret = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@"OAUTH_%@_%@_SECRET", prefix, provider]]; + if (theKey == NULL || theSecret == NULL) + return(nil); + self.key = theKey; + self.secret = theSecret; + } + return self; +} + +- (void)dealloc +{ + [key release]; + [secret release]; + [super dealloc]; +} + +#pragma mark - + +- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix +{ + [[NSUserDefaults standardUserDefaults] setObject:self.key forKey:[NSString stringWithFormat:@"OAUTH_%@_%@_KEY", prefix, provider]]; + [[NSUserDefaults standardUserDefaults] setObject:self.secret forKey:[NSString stringWithFormat:@"OAUTH_%@_%@_SECRET", prefix, provider]]; + [[NSUserDefaults standardUserDefaults] synchronize]; + return(0); +} + +@end diff --git a/Classes/OAuth/OAuthConsumer.h b/Classes/OAuth/OAuthConsumer.h new file mode 100755 index 00000000..1ac26b20 --- /dev/null +++ b/Classes/OAuth/OAuthConsumer.h @@ -0,0 +1,39 @@ +// +// OAuthConsumer.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "OAToken.h" +#import "OAConsumer.h" +#import "OAMutableURLRequest.h" +#import "NSString+URLEncoding.h" +#import "NSMutableURLRequest+Parameters.h" +#import "NSURL+Base.h" +#import "OASignatureProviding.h" +#import "OAHMAC_SHA1SignatureProvider.h" +#import "OAPlaintextSignatureProvider.h" +#import "OARequestParameter.h" +#import "OAServiceTicket.h" +#import "OADataFetcher.h" +#import "OAAsynchronousDataFetcher.h" \ No newline at end of file diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.h b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.h new file mode 100644 index 00000000..2d45b512 --- /dev/null +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.h @@ -0,0 +1,89 @@ +// +// SHKOAuthSharer.h +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" +#import "SHKOAuthView.h" +#import "OAuthConsumer.h" + +@interface SHKOAuthSharer : SHKSharer +{ + NSString *consumerKey; + NSString *secretKey; + NSURL *authorizeCallbackURL; + + NSURL *authorizeURL; + NSURL *accessURL; + NSURL *requestURL; + + OAConsumer *consumer; + OAToken *requestToken; + OAToken *accessToken; + + id signatureProvider; + + NSDictionary *authorizeResponseQueryVars; +} + +@property (nonatomic, retain) NSString *consumerKey; +@property (nonatomic, retain) NSString *secretKey; +@property (nonatomic, retain) NSURL *authorizeCallbackURL; + +@property (nonatomic, retain) NSURL *authorizeURL; +@property (nonatomic, retain) NSURL *accessURL; +@property (nonatomic, retain) NSURL *requestURL; + +@property (retain) OAConsumer *consumer; +@property (retain) OAToken *requestToken; +@property (retain) OAToken *accessToken; + +@property (retain) id signatureProvider; + +@property (nonatomic, retain) NSDictionary *authorizeResponseQueryVars; + + + +#pragma mark - +#pragma mark OAuth Authorization + +- (void)tokenRequest; +- (void)tokenRequestModifyRequest:(OAMutableURLRequest *)oRequest; +- (void)tokenRequestTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data; +- (void)tokenRequestTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error; + +- (void)tokenAuthorize; + +- (void)tokenAccess; +- (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest; +- (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data; +- (void)tokenAccessTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error; + +- (void)storeAccessToken; +- (BOOL)restoreAccessToken; + + +@end diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m new file mode 100644 index 00000000..21b37a3c --- /dev/null +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m @@ -0,0 +1,272 @@ +// +// SHKOAuthSharer.m +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKOAuthSharer.h" +#import "SHKOAuthView.h" +#import "OAuthConsumer.h" + + +@implementation SHKOAuthSharer + +@synthesize consumerKey, secretKey, authorizeCallbackURL; +@synthesize authorizeURL, requestURL, accessURL; +@synthesize consumer, requestToken, accessToken; +@synthesize signatureProvider; +@synthesize authorizeResponseQueryVars; + + +- (void)dealloc +{ + [consumerKey release]; + [secretKey release]; + [authorizeCallbackURL release]; + [authorizeURL release]; + [requestURL release]; + [accessURL release]; + [consumer release]; + [requestToken release]; + [accessToken release]; + [signatureProvider release]; + [authorizeResponseQueryVars release]; + + [super dealloc]; +} + + + +#pragma mark - +#pragma mark Authorization + +- (BOOL)isAuthorized +{ + return [self restoreAccessToken]; +} + +- (void)promptAuthorization +{ + [self tokenRequest]; +} + + +#pragma mark Request + +- (void)tokenRequest +{ + [[SHKActivityIndicator currentIndicator] displayActivity:@"Connecting..."]; + + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:requestURL + consumer:consumer + token:nil // we don't have a Token yet + realm:nil // our service provider doesn't specify a realm + signatureProvider:signatureProvider]; + + + [oRequest setHTTPMethod:@"POST"]; + + [self tokenRequestModifyRequest:oRequest]; + + OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest + delegate:self + didFinishSelector:@selector(tokenRequestTicket:didFinishWithData:) + didFailSelector:@selector(tokenRequestTicket:didFailWithError:)]; + [fetcher start]; + [oRequest release]; + + //NSLog(@"%@", oRequest.URL); + //NSLog(@"request %@", [[NSString alloc] initWithData:[oRequest HTTPBody] encoding:NSUTF8StringEncoding]); +} + +- (void)tokenRequestModifyRequest:(OAMutableURLRequest *)oRequest +{ + // Subclass to add custom paramaters and headers +} + +- (void)tokenRequestTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data +{ + //NSLog(@"tokenRequestTicketResponse %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); + + [[SHKActivityIndicator currentIndicator] hide]; + + if (ticket.didSucceed) + { + NSString *responseBody = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + self.requestToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody]; + [responseBody release]; + + [self tokenAuthorize]; + } + + else + // TODO - better error handling here + [self tokenRequestTicket:ticket didFailWithError:[SHK error:@"There was a problem requesting authorization from %@", [self sharerTitle]]]; +} + +- (void)tokenRequestTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error +{ + [[SHKActivityIndicator currentIndicator] hide]; + + [[[[UIAlertView alloc] initWithTitle:@"Request Error" + message:error!=nil?[error localizedDescription]:@"There was an error while sharing" + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; +} + + +#pragma mark Authorize + +- (void)tokenAuthorize +{ + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?oauth_token=%@", authorizeURL.absoluteString, requestToken.key]]; + + SHKOAuthView *auth = [[SHKOAuthView alloc] initWithURL:url delegate:self]; + [[SHK currentHelper] showViewController:auth]; + [auth release]; +} + +- (void)tokenAuthorizeView:(SHKOAuthView *)authView didFinishWithSuccess:(BOOL)success queryParams:(NSMutableDictionary *)queryParams error:(NSError *)error; +{ + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; + + if (!success) + { + [[[[UIAlertView alloc] initWithTitle:@"Authorize Error" + message:error!=nil?[error localizedDescription]:@"There was an error while authorizing" + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + } + + else + { + self.authorizeResponseQueryVars = queryParams; + + [self tokenAccess]; + } +} + + +#pragma mark Access + +- (void)tokenAccess +{ + [[SHKActivityIndicator currentIndicator] displayActivity:@"Authenticating..."]; + + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:accessURL + consumer:consumer + token:requestToken + realm:nil // our service provider doesn't specify a realm + signatureProvider:signatureProvider]; // use the default method, HMAC-SHA1 + + [oRequest setHTTPMethod:@"POST"]; + + [self tokenAccessModifyRequest:oRequest]; + + OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest + delegate:self + didFinishSelector:@selector(tokenAccessTicket:didFinishWithData:) + didFailSelector:@selector(tokenAccessTicket:didFailWithError:)]; + [fetcher start]; + [oRequest release]; +} + +- (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest +{ + // Subclass to add custom paramaters or headers +} + +- (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data +{ + //NSLog(@"tokenAccessTicketResponse %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); + + [[SHKActivityIndicator currentIndicator] hide]; + + if (ticket.didSucceed) + { + NSString *responseBody = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + self.accessToken = [[OAToken alloc] initWithHTTPResponseBody:responseBody]; + [responseBody release]; + + [self storeAccessToken]; + + if (shareAfterAuth) + [self share]; + } + + + else + // TODO - better error handling here + [self tokenAccessTicket:ticket didFailWithError:[SHK error:@"There was a problem requesting access from %@", [self sharerTitle]]]; +} + +- (void)tokenAccessTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error +{ + [[SHKActivityIndicator currentIndicator] hide]; + + [[[[UIAlertView alloc] initWithTitle:@"Access Error" + message:error!=nil?[error localizedDescription]:@"There was an error while sharing" + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; +} + +- (void)storeAccessToken +{ + [SHK setAuthValue:accessToken.key + forKey:@"accessKey" + forSharer:[self sharerId]]; + + [SHK setAuthValue:accessToken.secret + forKey:@"accessSecret" + forSharer:[self sharerId]]; +} + +- (BOOL)restoreAccessToken +{ + self.consumer = [[[OAConsumer alloc] initWithKey:consumerKey secret:secretKey] autorelease]; + + if (accessToken != nil) + return YES; + + NSString *key = [SHK getAuthValueForKey:@"accessKey" + forSharer:[self sharerId]]; + + NSString *secret = [SHK getAuthValueForKey:@"accessSecret" + forSharer:[self sharerId]]; + + if (key != nil && secret != nil) + { + self.accessToken = [[[OAToken alloc] initWithKey:key secret:secret] autorelease]; + return accessToken != nil; + } + + return NO; +} + +@end diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h new file mode 100644 index 00000000..be5bef51 --- /dev/null +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h @@ -0,0 +1,172 @@ +// +// SHKSharer.h +// ShareKit +// +// Created by Nathan Weiner on 6/8/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHK.h" +#import "SHKCustomFormController.h" + + +@class SHKSharer; + +@protocol SHKSharerDelegate + +- (void)sharerStartedSending:(SHKSharer *)sharer; +- (void)sharerFinishedSending:(SHKSharer *)sharer; +- (void)sharer:(SHKSharer *)sharer failedWithError:(NSError *)error shouldRelogin:(BOOL)shouldRelogin; +- (void)sharerCancelledSending:(SHKSharer *)sharer; + +@end + + + +@interface SHKSharer : UINavigationController +{ + id shareDelegate; + + SHKItem *item; + SHKFormController *pendingForm; + SHKRequest *request; + + NSError *lastError; + + BOOL quiet; + BOOL shareAfterAuth; +} + +@property (nonatomic, retain) id shareDelegate; + +@property (retain) SHKItem *item; +@property (retain) SHKFormController *pendingForm; +@property (retain) SHKRequest *request; + +@property (nonatomic, retain) NSError *lastError; + +@property BOOL quiet; +@property BOOL shareAfterAuth; + + + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle; +- (NSString *)sharerTitle; ++ (NSString *)sharerId; +- (NSString *)sharerId; ++ (BOOL)canShareText; ++ (BOOL)canShareURL; ++ (BOOL)canShareImage; ++ (BOOL)canShareFile; ++ (BOOL)shareRequiresInternetConnection; ++ (BOOL)canShareOffline; ++ (BOOL)requiresAuthentication; ++ (BOOL)canShareType:(SHKShareType)type; ++ (BOOL)canAutoShare; + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + ++ (BOOL)canShare; +- (BOOL)shouldAutoShare; + +#pragma mark - +#pragma mark Initialization + +- (id)init; + + +#pragma mark - +#pragma mark Share Item Loading Convenience Methods + ++ (id)shareItem:(SHKItem *)i; + ++ (id)shareURL:(NSURL *)url; ++ (id)shareURL:(NSURL *)url title:(NSString *)title; + ++ (id)shareImage:(UIImage *)image title:(NSString *)title; + ++ (id)shareText:(NSString *)text; + ++ (id)shareFile:(NSData *)file filename:(NSString *)filename mimeType:(NSString *)mimeType title:(NSString *)title; + + +#pragma mark - +#pragma mark Commit Share + +- (void)share; + +#pragma mark - +#pragma mark Authentication + +- (BOOL)isAuthorized; +- (BOOL)authorize; +- (void)promptAuthorization; +- (NSString *)getAuthValueForKey:(NSString *)key; + +#pragma mark Authorization Form + +- (void)authorizationFormShow; +- (void)authorizationFormValidate:(SHKFormController *)form; +- (void)authorizationFormSave:(SHKFormController *)form; +- (NSArray *)authorizationFormFields; +- (NSString *)authorizationFormCaption; + + +#pragma mark - +#pragma mark API Implementation + +- (BOOL)validateItem; +- (BOOL)tryToSend; +- (BOOL)send; + +#pragma mark - +#pragma mark UI Implementation + +- (void)show; + +#pragma mark - +#pragma mark Share Form + +- (NSArray *)shareFormFieldsForType:(SHKShareType)type; +- (void)shareFormValidate:(SHKFormController *)form; +- (void)shareFormSave:(SHKFormController *)form; + +#pragma mark - +#pragma mark Delegate Notifications + +- (void)sendDidStart; +- (void)sendDidFinish; +- (void)sendDidFailShouldRelogin; +- (void)sendDidFailWithError:(NSError *)error; +- (void)sendDidFailWithError:(NSError *)error shouldRelogin:(BOOL)shouldRelogin; +- (void)sendDidCancel; + +@end + + + diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m new file mode 100644 index 00000000..7d05e77a --- /dev/null +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m @@ -0,0 +1,666 @@ + // +// SHKSharer.m +// ShareKit +// +// Created by Nathan Weiner on 6/8/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKSharer.h" +#import "SHKActivityIndicator.h" + +@implementation SHKSharer + +@synthesize shareDelegate; +@synthesize item, pendingForm, request; +@synthesize lastError; +@synthesize quiet, shareAfterAuth; + +- (void)dealloc +{ + [item release]; + [shareDelegate release]; + [pendingForm release]; + [request release]; + [lastError release]; + + [super dealloc]; +} + + +#pragma mark - +#pragma mark Configuration : Service Defination + +// Each service should subclass these and return YES/NO to indicate what type of sharing they support. +// Superclass defaults to NO so that subclasses only need to add methods for types they support + ++ (NSString *)sharerTitle +{ + return @""; +} + +- (NSString *)sharerTitle +{ + return [[self class] sharerTitle]; +} + ++ (NSString *)sharerId +{ + return NSStringFromClass([self class]); +} + +- (NSString *)sharerId +{ + return [[self class] sharerId]; +} + ++ (BOOL)canShareText +{ + return NO; +} + ++ (BOOL)canShareURL +{ + return NO; +} + ++ (BOOL)canShareImage +{ + return NO; +} + ++ (BOOL)canShareFile +{ + return NO; +} + ++ (BOOL)shareRequiresInternetConnection +{ + return YES; +} + ++ (BOOL)canShareOffline +{ + return YES; +} + ++ (BOOL)requiresAuthentication +{ + return YES; +} + ++ (BOOL)canShareType:(SHKShareType)type +{ + switch (type) + { + case SHKShareTypeURL: + return [self canShareURL]; + break; + + case SHKShareTypeImage: + return [self canShareImage]; + break; + + case SHKShareTypeText: + return [self canShareText]; + break; + + case SHKShareTypeFile: + return [self canShareFile]; + break; + } + return NO; +} + ++ (BOOL)canAutoShare +{ + return YES; +} + + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + +// Allows a subclass to programically disable/enable services depending on the current environment + ++ (BOOL)canShare +{ + return YES; +} + +- (BOOL)shouldAutoShare +{ + return [[NSUserDefaults standardUserDefaults] boolForKey:[NSString stringWithFormat:@"%@_shouldAutoShare", [self sharerId]]]; +} + + +#pragma mark - +#pragma mark Initialization + +- (id)init +{ + if (self = [super initWithNibName:nil bundle:nil]) + { + self.shareDelegate = self; + self.item = [[[SHKItem alloc] init] autorelease]; + } + return self; +} + + +#pragma mark - +#pragma mark Share Item Loading Convenience Methods + ++ (id)shareItem:(SHKItem *)i +{ + [SHK pushOnFavorites:[self sharerId] forType:i.shareType]; + + switch (i.shareType) + { + case SHKShareTypeURL: + return [self shareURL:i.URL title:i.title]; + break; + + case SHKShareTypeImage: + return [self shareImage:i.image title:i.title]; + break; + + case SHKShareTypeText: + return [self shareText:i.text]; + break; + + case SHKShareTypeFile: + return [self shareFile:i.data filename:i.filename mimeType:i.mimeType title:i.title]; + break; + } + + return nil; +} + ++ (id)shareURL:(NSURL *)url +{ + return [self shareURL:url title:nil]; +} + ++ (id)shareURL:(NSURL *)url title:(NSString *)title +{ + // Create controller and set share options + SHKSharer *controller = [[self alloc] init]; + controller.item.shareType = SHKShareTypeURL; + controller.item.URL = url; + controller.item.title = title; + + // share and/or show UI + [controller share]; + + return [controller autorelease]; +} + ++ (id)shareImage:(UIImage *)image title:(NSString *)title +{ + // Create controller and set share options + SHKSharer *controller = [[self alloc] init]; + controller.item.shareType = SHKShareTypeImage; + controller.item.image = image; + controller.item.title = title; + + // share and/or show UI + [controller share]; + + return [controller autorelease]; +} + ++ (id)shareText:(NSString *)text +{ + // Create controller and set share options + SHKSharer *controller = [[self alloc] init]; + controller.item.shareType = SHKShareTypeText; + controller.item.text = text; + + // share and/or show UI + [controller share]; + + return [controller autorelease]; +} + ++ (id)shareFile:(NSData *)file filename:(NSString *)filename mimeType:(NSString *)mimeType title:(NSString *)title +{ + // Create controller and set share options + SHKSharer *controller = [[self alloc] init]; + controller.item.shareType = SHKShareTypeFile; + controller.item.data = file; + controller.item.filename = filename; + controller.item.mimeType = mimeType; + controller.item.title = title; + + // share and/or show UI + [controller share]; + + return [controller autorelease]; +} + + +#pragma mark - +#pragma mark Commit Share + +- (void)share +{ + // isAuthorized - If service requires login and details have not been saved, present login dialog + if (![self authorize]) + self.shareAfterAuth = YES; + + // A. First check if auto share is set + // B. If it is, try to send + // If either A or B fail, display the UI + else if (![self shouldAutoShare] || ![self tryToSend]) + [self show]; +} + + +#pragma mark - +#pragma mark Authentication + +- (BOOL)isAuthorized +{ + if (![[self class] requiresAuthentication]) + return YES; + + // Default implementation assumes the service needs all values from authorization keys. + // Subclass to customize requirements + + NSString *sharerId = [self sharerId]; + NSArray *fields = [self authorizationFormFields]; + for (SHKFormFieldSettings *field in fields) + { + if (![SHK getAuthValueForKey:field.key forSharer:sharerId]) + return NO; + } + + return YES; +} + +- (BOOL)authorize +{ + if ([self isAuthorized]) + return YES; + + else + [self promptAuthorization]; + + return NO; +} + +- (void)promptAuthorization +{ + if ([[self class] shareRequiresInternetConnection] && ![SHK connected]) + { + if (!quiet) + { + [[[[UIAlertView alloc] initWithTitle:@"Offline" + message:[NSString stringWithFormat:@"You must be online to login to %@", [self sharerTitle]] + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + } + return; + } + + [self authorizationFormShow]; +} + +- (NSString *)getAuthValueForKey:(NSString *)key +{ + return [SHK getAuthValueForKey:key forSharer:[self sharerId]]; +} + +- (void)setShouldAutoShare:(BOOL)b +{ + return [[NSUserDefaults standardUserDefaults] setBool:b forKey:[NSString stringWithFormat:@"%@_shouldAutoShare", [self sharerId]]]; +} + +#pragma mark Authorization Form + +- (void)authorizationFormShow +{ + // Create the form + SHKCustomFormController *form = [[SHKCustomFormController alloc] initWithStyle:UITableViewStyleGrouped title:@"Login" rightButtonTitle:@"Login"]; + [form addSection:[self authorizationFormFields] header:nil footer:[self authorizationFormCaption]]; + form.delegate = self; + form.validateSelector = @selector(authorizationFormValidate:); + form.saveSelector = @selector(authorizationFormSave:); + form.autoSelect = YES; + + [[SHK currentHelper] showViewController:form]; + [form release]; +} + +- (void)authorizationFormValidate:(SHKFormController *)form +{ + /* + + Services should subclass this. + You can get a dictionary of the field values from [form formValues] + + -- + + You should perform one of the following actions: + + 1. Display an error - If the user input was incorrect, display an error to the user and tell them what to do to fix it + + 2. Save the form - If everything is correct call [form saveForm] + + 3. Display a pending indicator - If you need to authorize the details on the server, display an activity indicator with [form displayActivity:@"DESCRIPTION OF WHAT YOU ARE DOING"] + After your process completes be sure to perform either 1 or 2 above. + + */ +} + +- (void)authorizationFormSave:(SHKFormController *)form +{ + // -- Save values + NSDictionary *formValues = [form formValues]; + + NSString *value; + NSString *sharerId = [self sharerId]; + NSArray *fields = [[[form sections] objectAtIndex:0] objectForKey:@"rows"]; + for(SHKFormFieldSettings *field in fields) + { + value = [formValues objectForKey:field.key]; + [SHK setAuthValue:value forKey:field.key forSharer:sharerId]; + } + + // -- Try to share again + [self share]; +} + +- (NSArray *)authorizationFormFields +{ + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Username" key:@"username" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:@"Password" key:@"password" type:SHKFormFieldTypePassword start:nil], + nil]; +} + +- (NSString *)authorizationFormCaption +{ + return nil; +} + + + + +#pragma mark - +#pragma mark UI Implementation + +- (void)show +{ + NSArray *shareFormFields = [self shareFormFieldsForType:item.shareType]; + + if (shareFormFields == nil) + [self tryToSend]; + + else + { + SHKCustomFormController *rootView = [[SHKCustomFormController alloc] initWithStyle:UITableViewStyleGrouped + title:nil + rightButtonTitle:[NSString stringWithFormat:@"Send to %@", [[self class] sharerTitle]] + ]; + [rootView addSection:[self shareFormFieldsForType:item.shareType] header:nil footer:item.URL!=nil?item.URL.absoluteString:nil]; + + if ([[self class] canAutoShare]) + { + [rootView addSection: + [NSArray arrayWithObject: + [SHKFormFieldSettings label:@"Auto Share" key:@"autoShare" type:SHKFormFieldTypeSwitch start:([self shouldAutoShare]?SHKFormFieldSwitchOn:SHKFormFieldSwitchOff)] + ] + header:nil + footer:@"Enable auto share to skip this step in the future."]; + } + + rootView.delegate = self; + rootView.validateSelector = @selector(shareFormValidate:); + rootView.saveSelector = @selector(shareFormSave:); + + [self pushViewController:rootView animated:NO]; + + [[SHK currentHelper] showViewController:self]; + } +} + + + + +#pragma mark - +#pragma mark Share Form + +- (NSArray *)shareFormFieldsForType:(SHKShareType)type +{ + if (type == SHKShareTypeURL) + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Title" key:@"title" type:SHKFormFieldTypeText start:item.title], + nil]; + + return nil; +} + +- (void)shareFormValidate:(SHKCustomFormController *)form +{ + /* + + Services should subclass this if they need to validate any data before sending. + You can get a dictionary of the field values from [form formValues] + + -- + + You should perform one of the following actions: + + 1. Display an error - If the user input was incorrect, display an error to the user and tell them what to do to fix it + + 2. Save the form - If everything is correct call [form save] + + 3. Display a pending indicator - If you need to authorize the details on the server, display an activity indicator with [form displayActivity:@"DESCRIPTION OF WHAT YOU ARE DOING"] + After your process completes be sure to perform either 1 or 2 above. + + */ + + + // default does no checking and proceeds to share + [form saveForm]; +} + +- (void)shareFormSave:(SHKFormController *)form +{ + // Update item with new values from form + NSDictionary *formValues = [form formValues]; + for(NSString *key in formValues) + { + if ([key isEqualToString:@"title"]) + item.title = [formValues objectForKey:key]; + + else if ([key isEqualToString:@"text"]) + item.text = [formValues objectForKey:key]; + + else if ([key isEqualToString:@"tags"]) + item.tags = [formValues objectForKey:key]; + + else + [item setCustomValue:[formValues objectForKey:key] forKey:key]; + } + + // Update shouldAutoShare + NSDictionary *advancedOptions = [form formValuesForSection:1]; + if ([advancedOptions objectForKey:@"autoShare"] != nil) + [self setShouldAutoShare:[[advancedOptions objectForKey:@"autoShare"] isEqualToString:SHKFormFieldSwitchOn]]; + + // Send the share + [self tryToSend]; +} + + +#pragma mark - +#pragma mark API Implementation + +- (BOOL)validateItem +{ + switch (item.shareType) + { + case SHKShareTypeURL: + return (item.URL != nil); + break; + + case SHKShareTypeImage: + return (item.image != nil); + break; + + case SHKShareTypeText: + return (item.text != nil); + break; + } + + return NO; +} + +- (BOOL)tryToSend +{ + if (![[self class] shareRequiresInternetConnection] || [SHK connected]) + return [self send]; + + else if ([[self class] canShareOffline]) + return [SHK addToOfflineQueue:item forSharer:[self sharerId]]; + + else if (!quiet) + { + [[[[UIAlertView alloc] initWithTitle:@"Offline" + message:[NSString stringWithFormat:@"You must be online in order to share with %@", [self sharerTitle]] + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + + return YES; + } + + + return NO; +} + +- (BOOL)send +{ + // Does not actually send anything. + // Your subclass should implement the sending logic. + // There is no reason to call [super send] in your subclass + + // You should never call [XXX send] directly, you should use [XXX tryToSend]. TryToSend will perform an online check before trying to send. + return NO; +} + +#pragma mark - +#pragma mark Default UI Updating + +// These are used if you do not provide your own custom UI and delegate + + +- (void)sharerStartedSending:(SHKSharer *)sharer +{ + if (!quiet) + [[SHKActivityIndicator currentIndicator] displayActivity:[NSString stringWithFormat:@"Saving to %@", [[self class] sharerTitle]]]; +} + +- (void)sharerFinishedSending:(SHKSharer *)sharer +{ + if (!quiet) + [[SHKActivityIndicator currentIndicator] displayCompleted:@"Saved!"]; +} + +- (void)sharer:(SHKSharer *)sharer failedWithError:(NSError *)error shouldRelogin:(BOOL)shouldRelogin +{ + if (!quiet) + { + [[SHKActivityIndicator currentIndicator] hide]; + + [[[[UIAlertView alloc] initWithTitle:@"Error" + message:sharer.lastError!=nil?[sharer.lastError localizedDescription]:@"There was an error while sharing" + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + + if (shouldRelogin) + [self promptAuthorization]; + } +} + +- (void)sharerCancelledSending:(SHKSharer *)sharer +{ + +} + + + +#pragma mark - + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + + +#pragma mark - +#pragma mark Delegate Notifications + +- (void)sendDidStart +{ + if ([shareDelegate respondsToSelector:@selector(sharerStartedSending:)]) + [shareDelegate performSelector:@selector(sharerStartedSending:) withObject:self]; +} + +- (void)sendDidFinish +{ + if ([shareDelegate respondsToSelector:@selector(sharerFinishedSending:)]) + [shareDelegate performSelector:@selector(sharerFinishedSending:) withObject:self]; +} + +- (void)sendDidFailShouldRelogin +{ + [self sendDidFailWithError:[SHK error:@"Could not authenticate you. Please relogin."] shouldRelogin:YES]; +} + +- (void)sendDidFailWithError:(NSError *)error +{ + [self sendDidFailWithError:error shouldRelogin:NO]; +} + +- (void)sendDidFailWithError:(NSError *)error shouldRelogin:(BOOL)shouldRelogin +{ + self.lastError = error; + + if ([shareDelegate respondsToSelector:@selector(sharer:failedWithError:shouldRelogin:)]) + [(SHKSharer *)shareDelegate sharer:self failedWithError:error shouldRelogin:shouldRelogin]; +} + +- (void)sendDidCancel +{ + if ([shareDelegate respondsToSelector:@selector(sharerCancelledSending:)]) + [shareDelegate performSelector:@selector(sharerCancelledSending:) withObject:self]; +} + + +@end diff --git a/Classes/ShareKit/Core/Categories/UIWebView+SHK.h b/Classes/ShareKit/Core/Categories/UIWebView+SHK.h new file mode 100644 index 00000000..94d420a7 --- /dev/null +++ b/Classes/ShareKit/Core/Categories/UIWebView+SHK.h @@ -0,0 +1,38 @@ +// +// UIWebView+SHK.h +// ShareKit +// +// Created by Nathan Weiner on 6/16/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface UIWebView (SHK) + +// Retrieves the title from the page loaded in a UIWebView +// Useful for providing a title when sharing URLs + +- (NSString *)pageTitle; + +@end diff --git a/Classes/ShareKit/Core/Categories/UIWebView+SHK.m b/Classes/ShareKit/Core/Categories/UIWebView+SHK.m new file mode 100644 index 00000000..3570617f --- /dev/null +++ b/Classes/ShareKit/Core/Categories/UIWebView+SHK.m @@ -0,0 +1,37 @@ +// +// UIWebView+SHK.m +// ShareKit +// +// Created by Nathan Weiner on 6/16/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "UIWebView+SHK.h" + +@implementation UIWebView (SHK) + +- (NSString *)pageTitle +{ + return [self stringByEvaluatingJavaScriptFromString:@"document.title"]; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/Keychain/SFHFKeychainUtils.h b/Classes/ShareKit/Core/Helpers/Keychain/SFHFKeychainUtils.h new file mode 100644 index 00000000..70b83aca --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/Keychain/SFHFKeychainUtils.h @@ -0,0 +1,41 @@ +// +// SFHFKeychainUtils.h +// +// Created by Buzz Andersen on 10/20/08. +// Based partly on code by Jonathan Wight, Jon Crosby, and Mike Malone. +// Copyright 2008 Sci-Fi Hi-Fi. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#import + + +@interface SFHFKeychainUtils : NSObject { + +} + ++ (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error; ++ (BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error; ++ (BOOL) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error; + +@end \ No newline at end of file diff --git a/Classes/ShareKit/Core/Helpers/Keychain/SFHFKeychainUtils.m b/Classes/ShareKit/Core/Helpers/Keychain/SFHFKeychainUtils.m new file mode 100644 index 00000000..b05ed5f8 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/Keychain/SFHFKeychainUtils.m @@ -0,0 +1,434 @@ +// +// SFHFKeychainUtils.m +// +// Created by Buzz Andersen on 10/20/08. +// Based partly on code by Jonathan Wight, Jon Crosby, and Mike Malone. +// Copyright 2008 Sci-Fi Hi-Fi. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#import "SFHFKeychainUtils.h" +#import + +static NSString *SFHFKeychainUtilsErrorDomain = @"SFHFKeychainUtilsErrorDomain"; + +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR +@interface SFHFKeychainUtils (PrivateMethods) ++ (SecKeychainItemRef) getKeychainItemReferenceForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error; +@end +#endif + +@implementation SFHFKeychainUtils + +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR + ++ (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error { + if (!username || !serviceName) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil]; + return nil; + } + + SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error]; + + if (*error || !item) { + return nil; + } + + // from Advanced Mac OS X Programming, ch. 16 + UInt32 length; + char *password; + SecKeychainAttribute attributes[8]; + SecKeychainAttributeList list; + + attributes[0].tag = kSecAccountItemAttr; + attributes[1].tag = kSecDescriptionItemAttr; + attributes[2].tag = kSecLabelItemAttr; + attributes[3].tag = kSecModDateItemAttr; + + list.count = 4; + list.attr = attributes; + + OSStatus status = SecKeychainItemCopyContent(item, NULL, &list, &length, (void **)&password); + + if (status != noErr) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil]; + return nil; + } + + NSString *passwordString = nil; + + if (password != NULL) { + char passwordBuffer[1024]; + + if (length > 1023) { + length = 1023; + } + strncpy(passwordBuffer, password, length); + + passwordBuffer[length] = '\0'; + passwordString = [NSString stringWithCString:passwordBuffer]; + } + + SecKeychainItemFreeContent(&list, password); + + CFRelease(item); + + return passwordString; +} + ++ (void) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error { + if (!username || !password || !serviceName) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil]; + return; + } + + OSStatus status = noErr; + + SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error]; + + if (*error && [*error code] != noErr) { + return; + } + + *error = nil; + + if (item) { + status = SecKeychainItemModifyAttributesAndData(item, + NULL, + strlen([password UTF8String]), + [password UTF8String]); + + CFRelease(item); + } + else { + status = SecKeychainAddGenericPassword(NULL, + strlen([serviceName UTF8String]), + [serviceName UTF8String], + strlen([username UTF8String]), + [username UTF8String], + strlen([password UTF8String]), + [password UTF8String], + NULL); + } + + if (status != noErr) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil]; + } +} + ++ (void) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error { + if (!username || !serviceName) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: 2000 userInfo: nil]; + return; + } + + *error = nil; + + SecKeychainItemRef item = [SFHFKeychainUtils getKeychainItemReferenceForUsername: username andServiceName: serviceName error: error]; + + if (*error && [*error code] != noErr) { + return; + } + + OSStatus status; + + if (item) { + status = SecKeychainItemDelete(item); + + CFRelease(item); + } + + if (status != noErr) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil]; + } +} + ++ (SecKeychainItemRef) getKeychainItemReferenceForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error { + if (!username || !serviceName) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil]; + return nil; + } + + *error = nil; + + SecKeychainItemRef item; + + OSStatus status = SecKeychainFindGenericPassword(NULL, + strlen([serviceName UTF8String]), + [serviceName UTF8String], + strlen([username UTF8String]), + [username UTF8String], + NULL, + NULL, + &item); + + if (status != noErr) { + if (status != errSecItemNotFound) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil]; + } + + return nil; + } + + return item; +} + +#else + ++ (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error { + if (!username || !serviceName) { + if (error != nil) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil]; + } + return nil; + } + + if (error != nil) { + *error = nil; + } + + // Set up a query dictionary with the base query attributes: item type (generic), username, and service + + NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecAttrService, nil] autorelease]; + NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, username, serviceName, nil] autorelease]; + + NSMutableDictionary *query = [[[NSMutableDictionary alloc] initWithObjects: objects forKeys: keys] autorelease]; + + // First do a query for attributes, in case we already have a Keychain item with no password data set. + // One likely way such an incorrect item could have come about is due to the previous (incorrect) + // version of this code (which set the password as a generic attribute instead of password data). + + NSDictionary *attributeResult = NULL; + NSMutableDictionary *attributeQuery = [query mutableCopy]; + [attributeQuery setObject: (id) kCFBooleanTrue forKey:(id) kSecReturnAttributes]; + OSStatus status = SecItemCopyMatching((CFDictionaryRef) attributeQuery, (CFTypeRef *) &attributeResult); + + [attributeResult release]; + [attributeQuery release]; + + if (status != noErr) { + // No existing item found--simply return nil for the password + if (error != nil && status != errSecItemNotFound) { + //Only return an error if a real exception happened--not simply for "not found." + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil]; + } + + return nil; + } + + // We have an existing item, now query for the password data associated with it. + + NSData *resultData = nil; + NSMutableDictionary *passwordQuery = [query mutableCopy]; + [passwordQuery setObject: (id) kCFBooleanTrue forKey: (id) kSecReturnData]; + + status = SecItemCopyMatching((CFDictionaryRef) passwordQuery, (CFTypeRef *) &resultData); + + [resultData autorelease]; + [passwordQuery release]; + + if (status != noErr) { + if (status == errSecItemNotFound) { + // We found attributes for the item previously, but no password now, so return a special error. + // Users of this API will probably want to detect this error and prompt the user to + // re-enter their credentials. When you attempt to store the re-entered credentials + // using storeUsername:andPassword:forServiceName:updateExisting:error + // the old, incorrect entry will be deleted and a new one with a properly encrypted + // password will be added. + if (error != nil) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -1999 userInfo: nil]; + } + } + else { + // Something else went wrong. Simply return the normal Keychain API error code. + if (error != nil) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil]; + } + } + + return nil; + } + + NSString *password = nil; + + if (resultData) { + password = [[NSString alloc] initWithData: resultData encoding: NSUTF8StringEncoding]; + } + else { + // There is an existing item, but we weren't able to get password data for it for some reason, + // Possibly as a result of an item being incorrectly entered by the previous code. + // Set the -1999 error so the code above us can prompt the user again. + if (error != nil) { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -1999 userInfo: nil]; + } + } + + return [password autorelease]; +} + ++ (BOOL) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error +{ + if (!username || !password || !serviceName) + { + if (error != nil) + { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil]; + } + return NO; + } + + // See if we already have a password entered for these credentials. + NSError *getError = nil; + NSString *existingPassword = [SFHFKeychainUtils getPasswordForUsername: username andServiceName: serviceName error:&getError]; + + if ([getError code] == -1999) + { + // There is an existing entry without a password properly stored (possibly as a result of the previous incorrect version of this code. + // Delete the existing item before moving on entering a correct one. + + getError = nil; + + [self deleteItemForUsername: username andServiceName: serviceName error: &getError]; + + if ([getError code] != noErr) + { + if (error != nil) + { + *error = getError; + } + return NO; + } + } + else if ([getError code] != noErr) + { + if (error != nil) + { + *error = getError; + } + return NO; + } + + if (error != nil) + { + *error = nil; + } + + OSStatus status = noErr; + + if (existingPassword) + { + // We have an existing, properly entered item with a password. + // Update the existing item. + + if (![existingPassword isEqualToString:password] && updateExisting) + { + //Only update if we're allowed to update existing. If not, simply do nothing. + + NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, + kSecAttrService, + kSecAttrLabel, + kSecAttrAccount, + nil] autorelease]; + + NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, + serviceName, + serviceName, + username, + nil] autorelease]; + + NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease]; + + status = SecItemUpdate((CFDictionaryRef) query, (CFDictionaryRef) [NSDictionary dictionaryWithObject: [password dataUsingEncoding: NSUTF8StringEncoding] forKey: (NSString *) kSecValueData]); + } + } + else + { + // No existing entry (or an existing, improperly entered, and therefore now + // deleted, entry). Create a new entry. + + NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, + kSecAttrService, + kSecAttrLabel, + kSecAttrAccount, + kSecValueData, + nil] autorelease]; + + NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, + serviceName, + serviceName, + username, + [password dataUsingEncoding: NSUTF8StringEncoding], + nil] autorelease]; + + NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease]; + + status = SecItemAdd((CFDictionaryRef) query, NULL); + } + + if (error != nil && status != noErr) + { + // Something went wrong with adding the new item. Return the Keychain error code. + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil]; + + return NO; + } + + return YES; +} + ++ (BOOL) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error +{ + if (!username || !serviceName) + { + if (error != nil) + { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: -2000 userInfo: nil]; + } + return NO; + } + + if (error != nil) + { + *error = nil; + } + + NSArray *keys = [[[NSArray alloc] initWithObjects: (NSString *) kSecClass, kSecAttrAccount, kSecAttrService, kSecReturnAttributes, nil] autorelease]; + NSArray *objects = [[[NSArray alloc] initWithObjects: (NSString *) kSecClassGenericPassword, username, serviceName, kCFBooleanTrue, nil] autorelease]; + + NSDictionary *query = [[[NSDictionary alloc] initWithObjects: objects forKeys: keys] autorelease]; + + OSStatus status = SecItemDelete((CFDictionaryRef) query); + + if (error != nil && status != noErr) + { + *error = [NSError errorWithDomain: SFHFKeychainUtilsErrorDomain code: status userInfo: nil]; + + return NO; + } + + return YES; +} + +#endif + +@end \ No newline at end of file diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSMutableURLRequest+Parameters.h b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSMutableURLRequest+Parameters.h new file mode 100755 index 00000000..13bf9afa --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSMutableURLRequest+Parameters.h @@ -0,0 +1,35 @@ +// +// NSMutableURLRequest+Parameters.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "OARequestParameter.h" +#import "NSURL+Base.h" + + +@interface NSMutableURLRequest (OAParameterAdditions) + +- (NSArray *)parameters; +- (void)setParameters:(NSArray *)parameters; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSMutableURLRequest+Parameters.m b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSMutableURLRequest+Parameters.m new file mode 100755 index 00000000..24035ed8 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSMutableURLRequest+Parameters.m @@ -0,0 +1,97 @@ +// +// NSMutableURLRequest+Parameters.m +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSMutableURLRequest+Parameters.h" + + +@implementation NSMutableURLRequest (OAParameterAdditions) + +- (NSArray *)parameters +{ + NSString *encodedParameters; + BOOL shouldfree = NO; + + if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) + encodedParameters = [[self URL] query]; + else + { + // POST, PUT + shouldfree = YES; + encodedParameters = [[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding]; + } + + if ((encodedParameters == nil) || ([encodedParameters isEqualToString:@""])) + { + if (shouldfree) + [encodedParameters release]; + + return nil; + } + + NSArray *encodedParameterPairs = [encodedParameters componentsSeparatedByString:@"&"]; + NSMutableArray *requestParameters = [[[NSMutableArray alloc] initWithCapacity:16] autorelease]; + + for (NSString *encodedPair in encodedParameterPairs) + { + NSArray *encodedPairElements = [encodedPair componentsSeparatedByString:@"="]; + OARequestParameter *parameter = [OARequestParameter requestParameterWithName:[[encodedPairElements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] + value:[[encodedPairElements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + [requestParameters addObject:parameter]; + } + + // Cleanup + if (shouldfree) + [encodedParameters release]; + + return requestParameters; +} + +- (void)setParameters:(NSArray *)parameters +{ + NSMutableString *encodedParameterPairs = [NSMutableString stringWithCapacity:256]; + + int position = 1; + for (OARequestParameter *requestParameter in parameters) + { + [encodedParameterPairs appendString:[requestParameter URLEncodedNameValuePair]]; + if (position < [parameters count]) + [encodedParameterPairs appendString:@"&"]; + + position++; + } + + if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", [[self URL] URLStringWithoutQuery], encodedParameterPairs]]]; + else + { + // POST, PUT + NSData *postData = [encodedParameterPairs dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + [self setHTTPBody:postData]; + [self setValue:[NSString stringWithFormat:@"%d", [postData length]] forHTTPHeaderField:@"Content-Length"]; + [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + } +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSString+URLEncoding.h b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSString+URLEncoding.h new file mode 100755 index 00000000..de06fe77 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSString+URLEncoding.h @@ -0,0 +1,34 @@ +// +// NSString+URLEncoding.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface NSString (OAURLEncodingAdditions) + +- (NSString *)URLEncodedString; +- (NSString *)URLDecodedString; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSString+URLEncoding.m b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSString+URLEncoding.m new file mode 100755 index 00000000..540492de --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSString+URLEncoding.m @@ -0,0 +1,52 @@ +// +// NSString+URLEncoding.m +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSString+URLEncoding.h" + + +@implementation NSString (OAURLEncodingAdditions) + +- (NSString *)URLEncodedString +{ + NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)self, + NULL, + CFSTR("!*'();:@&=+$,/?%#[]"), + kCFStringEncodingUTF8); + [result autorelease]; + return result; +} + +- (NSString*)URLDecodedString +{ + NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, + (CFStringRef)self, + CFSTR(""), + kCFStringEncodingUTF8); + [result autorelease]; + return result; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSURL+Base.h b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSURL+Base.h new file mode 100755 index 00000000..5d12b696 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSURL+Base.h @@ -0,0 +1,34 @@ +// +// NSURL+Base.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface NSURL (OABaseAdditions) + +- (NSString *)URLStringWithoutQuery; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSURL+Base.m b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSURL+Base.m new file mode 100755 index 00000000..8d4d4209 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Categories/NSURL+Base.m @@ -0,0 +1,38 @@ +// +// NSURL+Base.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSURL+Base.h" + + +@implementation NSURL (OABaseAdditions) + +- (NSString *)URLStringWithoutQuery +{ + NSArray *parts = [[self absoluteString] componentsSeparatedByString:@"?"]; + return [parts objectAtIndex:0]; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/Base64Transcoder.c b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/Base64Transcoder.c new file mode 100755 index 00000000..a655581e --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/Base64Transcoder.c @@ -0,0 +1,230 @@ +/* + * Base64Transcoder.c + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Base64Transcoder.h" + +#include +#include + +const u_int8_t kBase64EncodeTable[64] = { + /* 0 */ 'A', /* 1 */ 'B', /* 2 */ 'C', /* 3 */ 'D', + /* 4 */ 'E', /* 5 */ 'F', /* 6 */ 'G', /* 7 */ 'H', + /* 8 */ 'I', /* 9 */ 'J', /* 10 */ 'K', /* 11 */ 'L', + /* 12 */ 'M', /* 13 */ 'N', /* 14 */ 'O', /* 15 */ 'P', + /* 16 */ 'Q', /* 17 */ 'R', /* 18 */ 'S', /* 19 */ 'T', + /* 20 */ 'U', /* 21 */ 'V', /* 22 */ 'W', /* 23 */ 'X', + /* 24 */ 'Y', /* 25 */ 'Z', /* 26 */ 'a', /* 27 */ 'b', + /* 28 */ 'c', /* 29 */ 'd', /* 30 */ 'e', /* 31 */ 'f', + /* 32 */ 'g', /* 33 */ 'h', /* 34 */ 'i', /* 35 */ 'j', + /* 36 */ 'k', /* 37 */ 'l', /* 38 */ 'm', /* 39 */ 'n', + /* 40 */ 'o', /* 41 */ 'p', /* 42 */ 'q', /* 43 */ 'r', + /* 44 */ 's', /* 45 */ 't', /* 46 */ 'u', /* 47 */ 'v', + /* 48 */ 'w', /* 49 */ 'x', /* 50 */ 'y', /* 51 */ 'z', + /* 52 */ '0', /* 53 */ '1', /* 54 */ '2', /* 55 */ '3', + /* 56 */ '4', /* 57 */ '5', /* 58 */ '6', /* 59 */ '7', + /* 60 */ '8', /* 61 */ '9', /* 62 */ '+', /* 63 */ '/' +}; + +/* +-1 = Base64 end of data marker. +-2 = White space (tabs, cr, lf, space) +-3 = Noise (all non whitespace, non-base64 characters) +-4 = Dangerous noise +-5 = Illegal noise (null byte) +*/ + +const int8_t kBase64DecodeTable[128] = { + /* 0x00 */ -5, /* 0x01 */ -3, /* 0x02 */ -3, /* 0x03 */ -3, + /* 0x04 */ -3, /* 0x05 */ -3, /* 0x06 */ -3, /* 0x07 */ -3, + /* 0x08 */ -3, /* 0x09 */ -2, /* 0x0a */ -2, /* 0x0b */ -2, + /* 0x0c */ -2, /* 0x0d */ -2, /* 0x0e */ -3, /* 0x0f */ -3, + /* 0x10 */ -3, /* 0x11 */ -3, /* 0x12 */ -3, /* 0x13 */ -3, + /* 0x14 */ -3, /* 0x15 */ -3, /* 0x16 */ -3, /* 0x17 */ -3, + /* 0x18 */ -3, /* 0x19 */ -3, /* 0x1a */ -3, /* 0x1b */ -3, + /* 0x1c */ -3, /* 0x1d */ -3, /* 0x1e */ -3, /* 0x1f */ -3, + /* ' ' */ -2, /* '!' */ -3, /* '"' */ -3, /* '#' */ -3, + /* '$' */ -3, /* '%' */ -3, /* '&' */ -3, /* ''' */ -3, + /* '(' */ -3, /* ')' */ -3, /* '*' */ -3, /* '+' */ 62, + /* ',' */ -3, /* '-' */ -3, /* '.' */ -3, /* '/' */ 63, + /* '0' */ 52, /* '1' */ 53, /* '2' */ 54, /* '3' */ 55, + /* '4' */ 56, /* '5' */ 57, /* '6' */ 58, /* '7' */ 59, + /* '8' */ 60, /* '9' */ 61, /* ':' */ -3, /* ';' */ -3, + /* '<' */ -3, /* '=' */ -1, /* '>' */ -3, /* '?' */ -3, + /* '@' */ -3, /* 'A' */ 0, /* 'B' */ 1, /* 'C' */ 2, + /* 'D' */ 3, /* 'E' */ 4, /* 'F' */ 5, /* 'G' */ 6, + /* 'H' */ 7, /* 'I' */ 8, /* 'J' */ 9, /* 'K' */ 10, + /* 'L' */ 11, /* 'M' */ 12, /* 'N' */ 13, /* 'O' */ 14, + /* 'P' */ 15, /* 'Q' */ 16, /* 'R' */ 17, /* 'S' */ 18, + /* 'T' */ 19, /* 'U' */ 20, /* 'V' */ 21, /* 'W' */ 22, + /* 'X' */ 23, /* 'Y' */ 24, /* 'Z' */ 25, /* '[' */ -3, + /* '\' */ -3, /* ']' */ -3, /* '^' */ -3, /* '_' */ -3, + /* '`' */ -3, /* 'a' */ 26, /* 'b' */ 27, /* 'c' */ 28, + /* 'd' */ 29, /* 'e' */ 30, /* 'f' */ 31, /* 'g' */ 32, + /* 'h' */ 33, /* 'i' */ 34, /* 'j' */ 35, /* 'k' */ 36, + /* 'l' */ 37, /* 'm' */ 38, /* 'n' */ 39, /* 'o' */ 40, + /* 'p' */ 41, /* 'q' */ 42, /* 'r' */ 43, /* 's' */ 44, + /* 't' */ 45, /* 'u' */ 46, /* 'v' */ 47, /* 'w' */ 48, + /* 'x' */ 49, /* 'y' */ 50, /* 'z' */ 51, /* '{' */ -3, + /* '|' */ -3, /* '}' */ -3, /* '~' */ -3, /* 0x7f */ -3 +}; + +const u_int8_t kBits_00000011 = 0x03; +const u_int8_t kBits_00001111 = 0x0F; +const u_int8_t kBits_00110000 = 0x30; +const u_int8_t kBits_00111100 = 0x3C; +const u_int8_t kBits_00111111 = 0x3F; +const u_int8_t kBits_11000000 = 0xC0; +const u_int8_t kBits_11110000 = 0xF0; +const u_int8_t kBits_11111100 = 0xFC; + +size_t EstimateBas64EncodedDataSize(size_t inDataSize) +{ +size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4; +theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72; +return(theEncodedDataSize); +} + +size_t EstimateBas64DecodedDataSize(size_t inDataSize) +{ +size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3; +//theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72; +return(theDecodedDataSize); +} + +bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize) +{ +size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize); +if (*ioOutputDataSize < theEncodedDataSize) + return(false); +*ioOutputDataSize = theEncodedDataSize; +const u_int8_t *theInPtr = (const u_int8_t *)inInputData; +u_int32_t theInIndex = 0, theOutIndex = 0; +for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0]; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +const size_t theRemainingBytes = inInputDataSize - theInIndex; +if (theRemainingBytes == 1) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = '='; + outOutputData[theOutIndex++] = '='; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +else if (theRemainingBytes == 2) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6]; + outOutputData[theOutIndex++] = '='; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +return(true); +} + +bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize) +{ +memset(ioOutputData, '.', *ioOutputDataSize); + +size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize); +if (*ioOutputDataSize < theDecodedDataSize) + return(false); +*ioOutputDataSize = 0; +const u_int8_t *theInPtr = (const u_int8_t *)inInputData; +u_int8_t *theOutPtr = (u_int8_t *)ioOutputData; +size_t theInIndex = 0, theOutIndex = 0; +u_int8_t theOutputOctet; +size_t theSequence = 0; +for (; theInIndex < inInputDataSize; ) + { + int8_t theSextet = 0; + + int8_t theCurrentInputOctet = theInPtr[theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + if (theSextet == -1) + break; + while (theSextet == -2) + { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + } + while (theSextet == -3) + { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + } + if (theSequence == 0) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100; + } + else if (theSequence == 1) + { + theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011; + theOutPtr[theOutIndex++] = theOutputOctet; + } + else if (theSequence == 2) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000; + } + else if (theSequence == 3) + { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111; + theOutPtr[theOutIndex++] = theOutputOctet; + } + else if (theSequence == 4) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000; + } + else if (theSequence == 5) + { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111; + theOutPtr[theOutIndex++] = theOutputOctet; + } + theSequence = (theSequence + 1) % 6; + if (theSequence != 2 && theSequence != 4) + theInIndex++; + } +*ioOutputDataSize = theOutIndex; +return(true); +} diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/Base64Transcoder.h b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/Base64Transcoder.h new file mode 100755 index 00000000..87520989 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/Base64Transcoder.h @@ -0,0 +1,36 @@ +/* + * Base64Transcoder.h + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +extern size_t EstimateBas64EncodedDataSize(size_t inDataSize); +extern size_t EstimateBas64DecodedDataSize(size_t inDataSize); + +extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize); +extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize); + diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/hmac.c b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/hmac.c new file mode 100755 index 00000000..eea9a707 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/hmac.c @@ -0,0 +1,86 @@ +// +// hmac.c +// OAuthConsumer +// +// Created by Jonathan Wight on 4/8/8. +// Copyright 2008 Jonathan Wight. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * Implementation of HMAC-SHA1. Adapted from example at http://tools.ietf.org/html/rfc2104 + + */ + +#include "sha1.h" + +#include +#include + +void hmac_sha1(const unsigned char *inText, size_t inTextLength, unsigned char* inKey, size_t inKeyLength, unsigned char *outDigest) +{ +const size_t B = 64; +const size_t L = 20; + +SHA1_CTX theSHA1Context; +unsigned char k_ipad[B + 1]; /* inner padding - key XORd with ipad */ +unsigned char k_opad[B + 1]; /* outer padding - key XORd with opad */ + +/* if key is longer than 64 bytes reset it to key=SHA1 (key) */ +if (inKeyLength > B) + { + SHA1Init(&theSHA1Context); + SHA1Update(&theSHA1Context, inKey, inKeyLength); + SHA1Final(inKey, &theSHA1Context); + inKeyLength = L; + } + +/* start out by storing key in pads */ +memset(k_ipad, 0, sizeof k_ipad); +memset(k_opad, 0, sizeof k_opad); +memcpy(k_ipad, inKey, inKeyLength); +memcpy(k_opad, inKey, inKeyLength); + +/* XOR key with ipad and opad values */ +int i; +for (i = 0; i < B; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + +/* +* perform inner SHA1 +*/ +SHA1Init(&theSHA1Context); /* init context for 1st pass */ +SHA1Update(&theSHA1Context, k_ipad, B); /* start with inner pad */ +SHA1Update(&theSHA1Context, (unsigned char *)inText, inTextLength); /* then text of datagram */ +SHA1Final((unsigned char *)outDigest, &theSHA1Context); /* finish up 1st pass */ + +/* +* perform outer SHA1 +*/ +SHA1Init(&theSHA1Context); /* init context for 2nd +* pass */ +SHA1Update(&theSHA1Context, k_opad, B); /* start with outer pad */ +SHA1Update(&theSHA1Context, outDigest, L); /* then results of 1st +* hash */ +SHA1Final(outDigest, &theSHA1Context); /* finish up 2nd pass */ + +} \ No newline at end of file diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/hmac.h b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/hmac.h new file mode 100755 index 00000000..51eca9f6 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/hmac.h @@ -0,0 +1,31 @@ +// +// hmac.h +// OAuthConsumer +// +// Created by Jonathan Wight on 4/8/8. +// Copyright 2008 Jonathan Wight. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef HMAC_H +#define HMAC_H 1 + +extern void hmac_sha1(const unsigned char *inText, int inTextLength, unsigned char* inKey, const unsigned int inKeyLength, unsigned char *outDigest); + +#endif /* HMAC_H */ \ No newline at end of file diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/sha1.c b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/sha1.c new file mode 100755 index 00000000..16f5dbcf --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/sha1.c @@ -0,0 +1,169 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd if true. */ +#if __LITTLE_ENDIAN__ +#define LITTLE_ENDIAN +#endif +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#include +#include + +#include "sha1.h" + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifdef LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) +{ +unsigned long a, b, c, d, e; +typedef union { + unsigned char c[64]; + unsigned long l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) +{ +unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +unsigned long i, j; +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} diff --git a/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/sha1.h b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/sha1.h new file mode 100755 index 00000000..f3218ee5 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/Crytpo/sha1.h @@ -0,0 +1,12 @@ + +// From http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/sha1.c + +typedef struct { + unsigned long state[5]; + unsigned long count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +extern void SHA1Init(SHA1_CTX* context); +extern void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); +extern void SHA1Final(unsigned char digest[20], SHA1_CTX* context); diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.h b/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.h new file mode 100644 index 00000000..20a23152 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.h @@ -0,0 +1,45 @@ +// +// OAAsynchronousDataFetcher.h +// OAuthConsumer +// +// Created by Zsombor Szabó on 12/3/08. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import "OAMutableURLRequest.h" + +@interface OAAsynchronousDataFetcher : NSObject { + OAMutableURLRequest *request; + NSHTTPURLResponse *response; + NSURLConnection *connection; + NSMutableData *responseData; + id delegate; + SEL didFinishSelector; + SEL didFailSelector; +} + ++ (id)asynchronousFetcherWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; +- (id)initWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; + +- (void)start; +- (void)cancel; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.m b/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.m new file mode 100644 index 00000000..58472bc8 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.m @@ -0,0 +1,134 @@ +// +// OAAsynchronousDataFetcher.m +// OAuthConsumer +// +// Created by Zsombor Szabó on 12/3/08. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "OAAsynchronousDataFetcher.h" + +#import "OAServiceTicket.h" + +@implementation OAAsynchronousDataFetcher + ++ (id)asynchronousFetcherWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector +{ + return [[[OAAsynchronousDataFetcher alloc] initWithRequest:aRequest delegate:aDelegate didFinishSelector:finishSelector didFailSelector:failSelector] autorelease]; +} + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector +{ + if (self = [super init]) + { + request = [aRequest retain]; + delegate = aDelegate; + didFinishSelector = finishSelector; + didFailSelector = failSelector; + } + return self; +} + +- (void)start +{ + [request prepare]; + + if (connection) + [connection release]; + + connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; + + if (connection) + { + if (responseData) + [responseData release]; + responseData = [[NSMutableData data] retain]; + } + else + { + OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request + response:nil + didSucceed:NO]; + [delegate performSelector:didFailSelector + withObject:ticket + withObject:nil]; + [ticket release]; + } +} + +- (void)cancel +{ + if (connection) + { + [connection cancel]; + [connection release]; + connection = nil; + } +} + +- (void)dealloc +{ + if (request) [request release]; + if (connection) [connection release]; + if (response) [response release]; + if (responseData) [responseData release]; + [super dealloc]; +} + +#pragma mark - +#pragma mark NSURLConnection methods + +- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)aResponse +{ + if (response) + [response release]; + response = [aResponse retain]; + [responseData setLength:0]; +} + +- (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)data +{ + [responseData appendData:data]; +} + +- (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error +{ + OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request + response:response + didSucceed:NO]; + [delegate performSelector:didFailSelector + withObject:ticket + withObject:error]; + + [ticket release]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection +{ + OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request + response:response + didSucceed:[(NSHTTPURLResponse *)response statusCode] < 400]; + [delegate performSelector:didFinishSelector + withObject:ticket + withObject:responseData]; + + [ticket release]; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAConsumer.h b/Classes/ShareKit/Core/Helpers/OAuth/OAConsumer.h new file mode 100755 index 00000000..73bdab65 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAConsumer.h @@ -0,0 +1,40 @@ +// +// OAConsumer.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface OAConsumer : NSObject { +@protected + NSString *key; + NSString *secret; +} +@property(retain) NSString *key; +@property(retain) NSString *secret; + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAConsumer.m b/Classes/ShareKit/Core/Helpers/OAuth/OAConsumer.m new file mode 100755 index 00000000..0582ad9d --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAConsumer.m @@ -0,0 +1,51 @@ +// +// OAConsumer.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "OAConsumer.h" + + +@implementation OAConsumer +@synthesize key, secret; + +#pragma mark init + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret +{ + if (self = [super init]) + { + self.key = aKey; + self.secret = aSecret; + } + return self; +} + +- (void)dealloc +{ + [key release]; + [secret release]; + [super dealloc]; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OADataFetcher.h b/Classes/ShareKit/Core/Helpers/OAuth/OADataFetcher.h new file mode 100755 index 00000000..74273e37 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OADataFetcher.h @@ -0,0 +1,45 @@ +// +// OADataFetcher.h +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "OAMutableURLRequest.h" +#import "OAServiceTicket.h" + + +@interface OADataFetcher : NSObject { +@private + OAMutableURLRequest *request; + NSHTTPURLResponse *response; + NSURLConnection *connection; + NSError *error; + NSData *responseData; + id delegate; + SEL didFinishSelector; + SEL didFailSelector; +} + +- (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OADataFetcher.m b/Classes/ShareKit/Core/Helpers/OAuth/OADataFetcher.m new file mode 100755 index 00000000..b9c6d67c --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OADataFetcher.m @@ -0,0 +1,65 @@ +// +// OADataFetcher.m +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OADataFetcher.h" + + +@implementation OADataFetcher + +- (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest + delegate:(id)aDelegate + didFinishSelector:(SEL)finishSelector + didFailSelector:(SEL)failSelector +{ + request = aRequest; + delegate = aDelegate; + didFinishSelector = finishSelector; + didFailSelector = failSelector; + + [request prepare]; + + responseData = [NSURLConnection sendSynchronousRequest:request + returningResponse:&response + error:&error]; + + if (response == nil || responseData == nil || error != nil) { + OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request + response:response + didSucceed:NO]; + [delegate performSelector:didFailSelector + withObject:ticket + withObject:error]; + } else { + OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request + response:response + didSucceed:[(NSHTTPURLResponse *)response statusCode] < 400]; + [delegate performSelector:didFinishSelector + withObject:ticket + withObject:responseData]; + } +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAHMAC_SHA1SignatureProvider.h b/Classes/ShareKit/Core/Helpers/OAuth/OAHMAC_SHA1SignatureProvider.h new file mode 100755 index 00000000..d259c4ea --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAHMAC_SHA1SignatureProvider.h @@ -0,0 +1,32 @@ +// +// OAHMAC_SHA1SignatureProvider.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OASignatureProviding.h" + + +@interface OAHMAC_SHA1SignatureProvider : NSObject +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAHMAC_SHA1SignatureProvider.m b/Classes/ShareKit/Core/Helpers/OAuth/OAHMAC_SHA1SignatureProvider.m new file mode 100755 index 00000000..432baf7a --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAHMAC_SHA1SignatureProvider.m @@ -0,0 +1,58 @@ +// +// OAHMAC_SHA1SignatureProvider.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAHMAC_SHA1SignatureProvider.h" +#import + +#include "Base64Transcoder.h" + +@implementation OAHMAC_SHA1SignatureProvider + +- (NSString *)name +{ + return @"HMAC-SHA1"; +} + +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret +{ + NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding]; + NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding]; + unsigned char result[20]; + CCHmac(kCCHmacAlgSHA1, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], result); + + //Base64 Encoding + + char base64Result[32]; + size_t theResultLength = 32; + Base64EncodeData(result, 20, base64Result, &theResultLength); + NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength]; + + NSString *base64EncodedResult = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding]; + + return [base64EncodedResult autorelease]; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.h b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.h new file mode 100755 index 00000000..fdf0a1a8 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.h @@ -0,0 +1,68 @@ +// +// OAMutableURLRequest.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OAConsumer.h" +#import "OAToken.h" +#import "OAHMAC_SHA1SignatureProvider.h" +#import "OASignatureProviding.h" +#import "NSMutableURLRequest+Parameters.h" +#import "NSURL+Base.h" + + +@interface OAMutableURLRequest : NSMutableURLRequest { +@protected + OAConsumer *consumer; + OAToken *token; + NSString *realm; + NSString *signature; + id signatureProvider; + NSString *nonce; + NSString *timestamp; + NSMutableDictionary *extraOAuthParameters; +} +@property(readonly) NSString *signature; +@property(readonly) NSString *nonce; + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider; + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider + nonce:(NSString *)aNonce + timestamp:(NSString *)aTimestamp; + +- (void)prepare; + +- (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)parameterValue; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m new file mode 100755 index 00000000..d32f759a --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m @@ -0,0 +1,231 @@ +// +// OAMutableURLRequest.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAMutableURLRequest.h" + + +@interface OAMutableURLRequest (Private) +- (void)_generateTimestamp; +- (void)_generateNonce; +- (NSString *)_signatureBaseString; +@end + +@implementation OAMutableURLRequest +@synthesize signature, nonce; + +#pragma mark init + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider +{ + if (self = [super initWithURL:aUrl + cachePolicy:NSURLRequestReloadIgnoringCacheData + timeoutInterval:10.0]) + { + consumer = [aConsumer retain]; + + // empty token for Unauthorized Request Token transaction + if (aToken == nil) + token = [[OAToken alloc] init]; + else + token = [aToken retain]; + + if (aRealm == nil) + realm = [[NSString alloc] initWithString:@""]; + else + realm = [aRealm retain]; + + // default to HMAC-SHA1 + if (aProvider == nil) + signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; + else + signatureProvider = [aProvider retain]; + + [self _generateTimestamp]; + [self _generateNonce]; + } + return self; +} + +// Setting a timestamp and nonce to known +// values can be helpful for testing +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider + nonce:(NSString *)aNonce + timestamp:(NSString *)aTimestamp +{ + if (self = [super initWithURL:aUrl + cachePolicy:NSURLRequestReloadIgnoringCacheData + timeoutInterval:10.0]) + { + consumer = [aConsumer retain]; + + // empty token for Unauthorized Request Token transaction + if (aToken == nil) + token = [[OAToken alloc] init]; + else + token = [aToken retain]; + + if (aRealm == nil) + realm = [[NSString alloc] initWithString:@""]; + else + realm = [aRealm retain]; + + // default to HMAC-SHA1 + if (aProvider == nil) + signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; + else + signatureProvider = [aProvider retain]; + + timestamp = [aTimestamp retain]; + nonce = [aNonce retain]; + } + return self; +} + +- (void)dealloc +{ + [consumer release]; + [token release]; + [realm release]; + [signatureProvider release]; + [timestamp release]; + [nonce release]; + [extraOAuthParameters release]; + [super dealloc]; +} + +#pragma mark - +#pragma mark Public + +- (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)parameterValue +{ + assert(parameterName && parameterValue); + + if (extraOAuthParameters == nil) { + extraOAuthParameters = [NSMutableDictionary new]; + } + + [extraOAuthParameters setObject:parameterValue forKey:parameterName]; +} + +- (void)prepare +{ + // sign + // Secrets must be urlencoded before concatenated with '&' + // TODO: if later RSA-SHA1 support is added then a little code redesign is needed + signature = [signatureProvider signClearText:[self _signatureBaseString] + withSecret:[NSString stringWithFormat:@"%@&%@", + [consumer.secret URLEncodedString], + [token.secret URLEncodedString]]]; + + // set OAuth headers + NSString *oauthToken; + if ([token.key isEqualToString:@""]) + oauthToken = @""; // not used on Request Token transactions + else + oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", ", [token.key URLEncodedString]]; + + NSMutableString *extraParameters = [NSMutableString string]; + + // Adding the optional parameters in sorted order isn't required by the OAuth spec, but it makes it possible to hard-code expected values in the unit tests. + for(NSString *parameterName in [[extraOAuthParameters allKeys] sortedArrayUsingSelector:@selector(compare:)]) + { + [extraParameters appendFormat:@", %@=\"%@\"", + [parameterName URLEncodedString], + [[extraOAuthParameters objectForKey:parameterName] URLEncodedString]]; + } + + NSString *oauthHeader = [NSString stringWithFormat:@"OAuth realm=\"%@\", oauth_consumer_key=\"%@\", %@oauth_signature_method=\"%@\", oauth_signature=\"%@\", oauth_timestamp=\"%@\", oauth_nonce=\"%@\", oauth_version=\"1.0\"%@", + [realm URLEncodedString], + [consumer.key URLEncodedString], + oauthToken, + [[signatureProvider name] URLEncodedString], + [signature URLEncodedString], + timestamp, + nonce, + extraParameters]; + + [self setValue:oauthHeader forHTTPHeaderField:@"Authorization"]; +} + +#pragma mark - +#pragma mark Private + +- (void)_generateTimestamp +{ + timestamp = [[NSString stringWithFormat:@"%d", time(NULL)] retain]; +} + +- (void)_generateNonce +{ + CFUUIDRef theUUID = CFUUIDCreate(NULL); + CFStringRef string = CFUUIDCreateString(NULL, theUUID); + NSMakeCollectable(theUUID); + nonce = (NSString *)string; +} + +- (NSString *)_signatureBaseString +{ + // OAuth Spec, Section 9.1.1 "Normalize Request Parameters" + // build a sorted array of both request parameters and OAuth header parameters + NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:(6 + [[self parameters] count])]; // 6 being the number of OAuth params in the Signature Base String + + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_consumer_key" value:consumer.key] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_signature_method" value:[signatureProvider name]] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_timestamp" value:timestamp] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_nonce" value:nonce] URLEncodedNameValuePair]]; + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_version" value:@"1.0"] URLEncodedNameValuePair]]; + + if (![token.key isEqualToString:@""]) { + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_token" value:token.key] URLEncodedNameValuePair]]; + } + + for (OARequestParameter *param in [self parameters]) { + [parameterPairs addObject:[param URLEncodedNameValuePair]]; + } + + NSArray *sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)]; + NSString *normalizedRequestParameters = [sortedPairs componentsJoinedByString:@"&"]; + + // OAuth Spec, Section 9.1.2 "Concatenate Request Elements" + NSString *ret = [NSString stringWithFormat:@"%@&%@&%@", + [self HTTPMethod], + [[[self URL] URLStringWithoutQuery] URLEncodedString], + [normalizedRequestParameters URLEncodedString]]; + + //NSLog(@"ret %@", ret); + + return ret; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAPlaintextSignatureProvider.h b/Classes/ShareKit/Core/Helpers/OAuth/OAPlaintextSignatureProvider.h new file mode 100755 index 00000000..96bb2f28 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAPlaintextSignatureProvider.h @@ -0,0 +1,31 @@ +// +// OAPlaintextSignatureProvider.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OASignatureProviding.h" + +@interface OAPlaintextSignatureProvider : NSObject +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAPlaintextSignatureProvider.m b/Classes/ShareKit/Core/Helpers/OAuth/OAPlaintextSignatureProvider.m new file mode 100755 index 00000000..6f0c1c3a --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAPlaintextSignatureProvider.m @@ -0,0 +1,43 @@ +// +// OAPlaintextSignatureProvider.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAPlaintextSignatureProvider.h" +#import "NSString+URLEncoding.h" + + +@implementation OAPlaintextSignatureProvider + +- (NSString *)name +{ + return @"PLAINTEXT"; +} + +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret +{ + return secret; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.h b/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.h new file mode 100755 index 00000000..fe64c700 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.h @@ -0,0 +1,53 @@ +// +// OAProblem.h +// OAuthConsumer +// +// Created by Alberto García Hierro on 03/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import + +enum { + kOAProblemSignatureMethodRejected = 0, + kOAProblemParameterAbsent, + kOAProblemVersionRejected, + kOAProblemConsumerKeyUnknown, + kOAProblemTokenRejected, + kOAProblemSignatureInvalid, + kOAProblemNonceUsed, + kOAProblemTimestampRefused, + kOAProblemTokenExpired, + kOAProblemTokenNotRenewable +}; + +@interface OAProblem : NSObject { + const NSString *problem; +} + +@property (readonly) const NSString *problem; + +- (id)initWithProblem:(const NSString *)aProblem; +- (id)initWithResponseBody:(const NSString *)response; + +- (BOOL)isEqualToProblem:(OAProblem *)aProblem; +- (BOOL)isEqualToString:(const NSString *)aProblem; +- (BOOL)isEqualTo:(id)aProblem; +- (int)code; + ++ (OAProblem *)problemWithResponseBody:(const NSString *)response; + ++ (const NSArray *)validProblems; + ++ (OAProblem *)SignatureMethodRejected; ++ (OAProblem *)ParameterAbsent; ++ (OAProblem *)VersionRejected; ++ (OAProblem *)ConsumerKeyUnknown; ++ (OAProblem *)TokenRejected; ++ (OAProblem *)SignatureInvalid; ++ (OAProblem *)NonceUsed; ++ (OAProblem *)TimestampRefused; ++ (OAProblem *)TokenExpired; ++ (OAProblem *)TokenNotRenewable; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.m b/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.m new file mode 100755 index 00000000..7a885a3c --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.m @@ -0,0 +1,165 @@ +// +// OAProblem.m +// OAuthConsumer +// +// Created by Alberto García Hierro on 03/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import "OAProblem.h" + +const NSString *signature_method_rejected = @"signature_method_rejected"; +const NSString *parameter_absent = @"parameter_absent"; +const NSString *version_rejected = @"version_rejected"; +const NSString *consumer_key_unknown = @"consumer_key_unknown"; +const NSString *token_rejected = @"token_rejected"; +const NSString *signature_invalid = @"signature_invalid"; +const NSString *nonce_used = @"nonce_used"; +const NSString *timestamp_refused = @"timestamp_refused"; +const NSString *token_expired = @"token_expired"; +const NSString *token_not_renewable = @"token_not_renewable"; + +@implementation OAProblem + +@synthesize problem; + +- (id)initWithPointer:(const NSString *) aPointer +{ + [super init]; + problem = aPointer; + return self; +} + +- (id)initWithProblem:(const NSString *) aProblem +{ + NSUInteger idx = [[OAProblem validProblems] indexOfObject:aProblem]; + if (idx == NSNotFound) { + return nil; + } + + return [self initWithPointer: [[OAProblem validProblems] objectAtIndex:idx]]; +} + +- (id)initWithResponseBody:(const NSString *) response +{ + NSArray *fields = [response componentsSeparatedByString:@"&"]; + for (NSString *field in fields) { + if ([field hasPrefix:@"oauth_problem="]) { + NSString *value = [[field componentsSeparatedByString:@"="] objectAtIndex:1]; + return [self initWithProblem:value]; + } + } + + return nil; +} + ++ (OAProblem *)problemWithResponseBody:(const NSString *) response +{ + return [[[OAProblem alloc] initWithResponseBody:response] autorelease]; +} + ++ (const NSArray *)validProblems +{ + static NSArray *array; + if (!array) { + array = [[NSArray alloc] initWithObjects:signature_method_rejected, + parameter_absent, + version_rejected, + consumer_key_unknown, + token_rejected, + signature_invalid, + nonce_used, + timestamp_refused, + token_expired, + token_not_renewable, + nil]; + } + + return array; +} + +- (BOOL)isEqualToProblem:(OAProblem *) aProblem +{ + return [problem isEqualToString:(NSString *)aProblem->problem]; +} + +- (BOOL)isEqualToString:(const NSString *) aProblem +{ + return [problem isEqualToString:(NSString *)aProblem]; +} + +- (BOOL)isEqualTo:(id) aProblem +{ + if ([aProblem isKindOfClass:[NSString class]]) { + return [self isEqualToString:aProblem]; + } + + if ([aProblem isKindOfClass:[OAProblem class]]) { + return [self isEqualToProblem:aProblem]; + } + + return NO; +} + +- (int)code { + return [[[self class] validProblems] indexOfObject:problem]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"OAuth Problem: %@", (NSString *)problem]; +} + +#pragma mark class_methods + ++ (OAProblem *)SignatureMethodRejected +{ + return [[[OAProblem alloc] initWithPointer:signature_method_rejected] autorelease]; +} + ++ (OAProblem *)ParameterAbsent +{ + return [[[OAProblem alloc] initWithPointer:parameter_absent] autorelease]; +} + ++ (OAProblem *)VersionRejected +{ + return [[[OAProblem alloc] initWithPointer:version_rejected] autorelease]; +} + ++ (OAProblem *)ConsumerKeyUnknown +{ + return [[[OAProblem alloc] initWithPointer:consumer_key_unknown] autorelease]; +} + ++ (OAProblem *)TokenRejected +{ + return [[[OAProblem alloc] initWithPointer:token_rejected] autorelease]; +} + ++ (OAProblem *)SignatureInvalid +{ + return [[[OAProblem alloc] initWithPointer:signature_invalid] autorelease]; +} + ++ (OAProblem *)NonceUsed +{ + return [[[OAProblem alloc] initWithPointer:nonce_used] autorelease]; +} + ++ (OAProblem *)TimestampRefused +{ + return [[[OAProblem alloc] initWithPointer:timestamp_refused] autorelease]; +} + ++ (OAProblem *)TokenExpired +{ + return [[[OAProblem alloc] initWithPointer:token_expired] autorelease]; +} + ++ (OAProblem *)TokenNotRenewable +{ + return [[[OAProblem alloc] initWithPointer:token_not_renewable] autorelease]; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OARequestParameter.h b/Classes/ShareKit/Core/Helpers/OAuth/OARequestParameter.h new file mode 100755 index 00000000..03eee3e0 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OARequestParameter.h @@ -0,0 +1,45 @@ +// +// OARequestParameter.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "NSString+URLEncoding.h" + + +@interface OARequestParameter : NSObject { +@protected + NSString *name; + NSString *value; +} +@property(retain) NSString *name; +@property(retain) NSString *value; + ++ (id)requestParameterWithName:(NSString *)aName value:(NSString *)aValue; +- (id)initWithName:(NSString *)aName value:(NSString *)aValue; +- (NSString *)URLEncodedName; +- (NSString *)URLEncodedValue; +- (NSString *)URLEncodedNameValuePair; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OARequestParameter.m b/Classes/ShareKit/Core/Helpers/OAuth/OARequestParameter.m new file mode 100755 index 00000000..59b6a8a6 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OARequestParameter.m @@ -0,0 +1,70 @@ +// +// OARequestParameter.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OARequestParameter.h" + + +@implementation OARequestParameter +@synthesize name, value; + ++ (id)requestParameterWithName:(NSString *)aName value:(NSString *)aValue +{ + return [[[OARequestParameter alloc] initWithName:aName value:aValue] autorelease]; +} + +- (id)initWithName:(NSString *)aName value:(NSString *)aValue +{ + if (self = [super init]) + { + self.name = aName; + self.value = aValue; + } + return self; +} + +- (void)dealloc +{ + [name release]; + [value release]; + [super dealloc]; +} + +- (NSString *)URLEncodedName +{ + return [self.name URLEncodedString]; +} + +- (NSString *)URLEncodedValue +{ + return [self.value URLEncodedString]; +} + +- (NSString *)URLEncodedNameValuePair +{ + return [NSString stringWithFormat:@"%@=%@", [self URLEncodedName], [self URLEncodedValue]]; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAServiceTicket.h b/Classes/ShareKit/Core/Helpers/OAuth/OAServiceTicket.h new file mode 100755 index 00000000..9a8eb348 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAServiceTicket.h @@ -0,0 +1,47 @@ +// +// OAServiceTicket.h +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OAMutableURLRequest.h" + + +@interface OAServiceTicket : NSObject { +@private + OAMutableURLRequest *request; + NSHTTPURLResponse *response; + NSData *data; + BOOL didSucceed; +} +@property(readonly) OAMutableURLRequest *request; +@property(readonly) NSHTTPURLResponse *response; +@property(readonly) NSData *data; +@property(readonly) BOOL didSucceed; +@property(readonly) NSString *body; + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse didSucceed:(BOOL)success; +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAServiceTicket.m b/Classes/ShareKit/Core/Helpers/OAuth/OAServiceTicket.m new file mode 100755 index 00000000..fb6e3b7c --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAServiceTicket.m @@ -0,0 +1,56 @@ +// +// OAServiceTicket.m +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAServiceTicket.h" + + +@implementation OAServiceTicket +@synthesize request, response, data, didSucceed; + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse didSucceed:(BOOL)success +{ + return [self initWithRequest:aRequest response:aResponse data:nil didSucceed:success]; +} + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success { + [super init]; + request = aRequest; + response = aResponse; + data = aData; + didSucceed = success; + return self; +} + +- (NSString *)body +{ + if (!data) { + return nil; + } + + return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OASignatureProviding.h b/Classes/ShareKit/Core/Helpers/OAuth/OASignatureProviding.h new file mode 100755 index 00000000..0c7e4f8c --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OASignatureProviding.h @@ -0,0 +1,34 @@ +// +// OASignatureProviding.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@protocol OASignatureProviding + +- (NSString *)name; +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAToken.h b/Classes/ShareKit/Core/Helpers/OAuth/OAToken.h new file mode 100755 index 00000000..8dd331e1 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAToken.h @@ -0,0 +1,41 @@ +// +// OAToken.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@interface OAToken : NSObject { +@protected + NSString *key; + NSString *secret; +} +@property(retain) NSString *key; +@property(retain) NSString *secret; + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; +- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; +- (id)initWithHTTPResponseBody:(NSString *)body; +- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAToken.m b/Classes/ShareKit/Core/Helpers/OAuth/OAToken.m new file mode 100755 index 00000000..d4f24911 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAToken.m @@ -0,0 +1,105 @@ +// +// OAToken.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAToken.h" + + +@implementation OAToken + +@synthesize key, secret; + +#pragma mark init + +- (id)init +{ + if (self = [super init]) + { + self.key = @""; + self.secret = @""; + } + return self; +} + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret +{ + if (self = [super init]) + { + self.key = aKey; + self.secret = aSecret; + } + return self; +} + +- (id)initWithHTTPResponseBody:(NSString *)body +{ + if (self = [super init]) + { + NSArray *pairs = [body componentsSeparatedByString:@"&"]; + + for (NSString *pair in pairs) { + NSArray *elements = [pair componentsSeparatedByString:@"="]; + if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token"]) { + self.key = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_secret"]) { + self.secret = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } + } + } + return self; +} + +- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix +{ + if (self = [super init]) + { + NSString *theKey = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@"OAUTH_%@_%@_KEY", prefix, provider]]; + NSString *theSecret = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@"OAUTH_%@_%@_SECRET", prefix, provider]]; + if (theKey == NULL || theSecret == NULL) + return(nil); + self.key = theKey; + self.secret = theSecret; + } + return self; +} + +- (void)dealloc +{ + [key release]; + [secret release]; + [super dealloc]; +} + +#pragma mark - + +- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix +{ + [[NSUserDefaults standardUserDefaults] setObject:self.key forKey:[NSString stringWithFormat:@"OAUTH_%@_%@_KEY", prefix, provider]]; + [[NSUserDefaults standardUserDefaults] setObject:self.secret forKey:[NSString stringWithFormat:@"OAUTH_%@_%@_SECRET", prefix, provider]]; + [[NSUserDefaults standardUserDefaults] synchronize]; + return(0); +} + +@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAuthConsumer.h b/Classes/ShareKit/Core/Helpers/OAuth/OAuthConsumer.h new file mode 100755 index 00000000..1ac26b20 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAuthConsumer.h @@ -0,0 +1,39 @@ +// +// OAuthConsumer.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "OAToken.h" +#import "OAConsumer.h" +#import "OAMutableURLRequest.h" +#import "NSString+URLEncoding.h" +#import "NSMutableURLRequest+Parameters.h" +#import "NSURL+Base.h" +#import "OASignatureProviding.h" +#import "OAHMAC_SHA1SignatureProvider.h" +#import "OAPlaintextSignatureProvider.h" +#import "OARequestParameter.h" +#import "OAServiceTicket.h" +#import "OADataFetcher.h" +#import "OAAsynchronousDataFetcher.h" \ No newline at end of file diff --git a/Classes/ShareKit/Core/Helpers/SHKRequest.h b/Classes/ShareKit/Core/Helpers/SHKRequest.h new file mode 100644 index 00000000..9e66adf5 --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/SHKRequest.h @@ -0,0 +1,74 @@ +// +// SHKRequest.h +// ShareKit +// +// Created by Nathan Weiner on 6/9/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface SHKRequest : NSObject +{ + NSURL *url; + NSString *params; + NSString *method; + NSDictionary *headerFields; + + id delegate; + SEL isFinishedSelector; + + NSURLConnection *connection; + + NSHTTPURLResponse *response; + NSDictionary *headers; + + NSMutableData *data; + NSString *result; + BOOL success; +} + +@property (retain) NSURL *url; +@property (retain) NSString *params; +@property (retain) NSString *method; +@property (retain) NSDictionary *headerFields; + +@property (assign) id delegate; +@property (assign) SEL isFinishedSelector; + +@property (retain) NSURLConnection *connection; + +@property (retain) NSHTTPURLResponse *response; +@property (retain) NSDictionary *headers; + +@property (retain) NSMutableData *data; +@property (retain, getter=getResult) NSString *result; +@property (nonatomic) BOOL success; + +- (id)initWithURL:(NSURL *)u params:(NSString *)p delegate:(id)d isFinishedSelector:(SEL)s method:(NSString *)m autostart:(BOOL)autostart; + +- (void)start; +- (void)finish; + + +@end diff --git a/Classes/ShareKit/Core/Helpers/SHKRequest.m b/Classes/ShareKit/Core/Helpers/SHKRequest.m new file mode 100644 index 00000000..243e6ccd --- /dev/null +++ b/Classes/ShareKit/Core/Helpers/SHKRequest.m @@ -0,0 +1,148 @@ +// +// SHKRequest.m +// ShareKit +// +// Created by Nathan Weiner on 6/9/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKRequest.h" + +#define SHK_TIMEOUT 90 + +@implementation SHKRequest + +@synthesize url, params, method, headerFields; +@synthesize delegate, isFinishedSelector; +@synthesize data, result, headers, response, connection; +@synthesize success; + +- (void)dealloc +{ + [url release]; + [params release]; + [method release]; + [headerFields release]; + [connection release]; + [data release]; + [result release]; + [response release]; + [super dealloc]; +} + +- (id)initWithURL:(NSURL *)u params:(NSString *)p delegate:(id)d isFinishedSelector:(SEL)s method:(NSString *)m autostart:(BOOL)autostart +{ + if (self = [super init]) + { + self.url = u; + self.params = p; + self.method = m; + + self.delegate = d; + self.isFinishedSelector = s; + + if (autostart) + [self start]; + } + + return self; +} + + +#pragma mark - + +- (void)start +{ + self.data = [[NSMutableData alloc] initWithLength:0]; + [data release]; + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData + timeoutInterval:SHK_TIMEOUT]; + + // overwrite header fields (generally for cookies) + if (headerFields != nil) + [request setAllHTTPHeaderFields:headerFields]; + + // Setup Request Data/Params + if (params != nil) + { + NSData *paramsData = [ NSData dataWithBytes:[params UTF8String] length:[params length] ]; + + // Fill Request + [request setHTTPMethod:method]; + [request setHTTPBody:paramsData]; + } + + // Start Connection + //NSLog(@"SHKRequest: %@?%@\n\n%@", url, params, [request allHTTPHeaderFields]); + self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; + [request release]; + [connection release]; +} + + +#pragma mark - + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)theResponse +{ + self.response = theResponse; + self.headers = [[response allHeaderFields] mutableCopy]; + [headers release]; + + [data setLength:0]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d +{ + [data appendData:d]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection +{ + [self finish]; +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + [self finish]; +} + +#pragma mark - + +- (void)finish +{ + self.success = response.statusCode == 200; + + if ([delegate respondsToSelector:isFinishedSelector]) + [delegate performSelector:isFinishedSelector withObject:self]; +} + +- (NSString *)getResult +{ + if (result == nil) + self.result = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + return result; +} + + +@end diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h new file mode 100644 index 00000000..46d0fa94 --- /dev/null +++ b/Classes/ShareKit/Core/SHK.h @@ -0,0 +1,120 @@ +// +// SHK.h +// ShareKit +// +// Created by Nathan Weiner on 6/10/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#define SHK_VERSION @"0.1.0" + + +#import +#import "SHKConfig.h" +#import "SHKItem.h" +#import "SHKActionSheet.h" +#import "SHKRequest.h" +#import "SHKActivityIndicator.h" +#import "SHKFormFieldSettings.h" +#import "UIWebView+SHK.h" + + +@class SHKActionSheet; +@class SHKViewControllerWrapper; + + +@interface SHK : NSObject +{ + UIViewController *rootViewController; + UIViewController *currentView; + UIViewController *pendingView; + BOOL isDismissingView; + + NSOperationQueue *offlineQueue; +} + +@property (nonatomic, retain) UIViewController *rootViewController; +@property (nonatomic, retain) UIViewController *currentView; +@property (nonatomic, retain) UIViewController *pendingView; +@property BOOL isDismissingView; + +@property (nonatomic, retain) NSOperationQueue *offlineQueue; + + + +#pragma mark - + ++ (SHK *)currentHelper; + ++ (NSDictionary *)sharersDictionary; + + +#pragma mark - +#pragma mark View Management + +- (void)showViewController:(UIViewController *)vc; +- (void)hideCurrentViewControllerAnimated:(BOOL)animated; +- (void)viewWasDismissed; +- (UIViewController *)getTopViewController; ++ (UIBarStyle)barStyle; + +#pragma mark - +#pragma mark Favorites + ++ (NSArray *)favoriteSharersForType:(SHKShareType)type; ++ (void)pushOnFavorites:(NSString *)className forType:(SHKShareType)type; ++ (void)setFavorites:(NSArray *)favs forType:(SHKShareType)type; + ++ (NSDictionary *)getUserExclusions; ++ (void)setUserExclusions:(NSDictionary *)exclusions; + + +#pragma mark - +#pragma mark Credentials + ++ (NSString *)getAuthValueForKey:(NSString *)key forSharer:(NSString *)sharerId; ++ (void)setAuthValue:(NSString *)value forKey:(NSString *)key forSharer:(NSString *)sharerId; + +#pragma mark - +#pragma mark Offline Support + ++ (void)flushOfflineQueue; ++ (NSString *)offlineQueueListPath; ++ (NSMutableArray *)getOfflineQueueList; ++ (void)saveOfflineQueueList:(NSMutableArray *)queueList; ++ (BOOL)addToOfflineQueue:(SHKItem *)item forSharer:(NSString *)sharerId; + +#pragma mark - + ++ (NSError *)error:(NSString *)description, ...; + +#pragma mark - +#pragma mark Network + ++ (BOOL)connected; + +@end + + +NSString * SHKEncode(NSString * value); +NSString * SHKEncodeURL(NSURL * value); + diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m new file mode 100644 index 00000000..d6b88744 --- /dev/null +++ b/Classes/ShareKit/Core/SHK.m @@ -0,0 +1,460 @@ +// +// SHK.m +// ShareKit +// +// Created by Nathan Weiner on 6/10/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHK.h" +#import "SHKActivityIndicator.h" +#import "SHKViewControllerWrapper.h" +#import "SHKNavController.h" +#import "SHKActionSheet.h" +#import "SHKOfflineSharer.h" +#import "SFHFKeychainUtils.h" +#import "Reachability.h" + + +@implementation SHK + +@synthesize rootViewController, currentView, pendingView, isDismissingView; +@synthesize offlineQueue; + +static SHK *currentHelper = nil; + + + ++ (SHK *)currentHelper +{ + if (currentHelper == nil) + currentHelper = [[SHK alloc] init]; + + return currentHelper; +} + + +- (void)dealloc +{ + [rootViewController release]; + [currentView release]; + [pendingView release]; + [offlineQueue release]; + [super dealloc]; +} + + + +#pragma mark - +#pragma mark View Management + ++ (void)setRootViewController:(UIViewController *)vc +{ + [[self currentHelper] setRootViewController:vc]; +} + +- (void)showViewController:(UIViewController *)vc +{ + if (rootViewController == nil) + { + // Try to find the root view controller programmically + + // Find the top window (that is not an alert view or other window) + UIWindow *topWindow = [[UIApplication sharedApplication] keyWindow]; + if (topWindow.windowLevel != UIWindowLevelNormal) + { + NSArray *windows = [[UIApplication sharedApplication] windows]; + for(topWindow in windows) + { + if (topWindow.windowLevel == UIWindowLevelNormal) + break; + } + } + + UIView *rootView = [[topWindow subviews] objectAtIndex:0]; + id nextResponder = [rootView nextResponder]; + + if ([nextResponder isKindOfClass:[UIViewController class]]) + self.rootViewController = nextResponder; + + else + NSAssert(NO, @"ShareKit: Could not find a root view controller. You can assign one manually by calling [[SHK currentHelper] setRootViewController:YOURROOTVIEWCONTROLLER]."); + } + + // Find the top most view controller being displayed (so we can add the modal view to it and not one that is hidden) + UIViewController *topViewController = [self getTopViewController]; + if (topViewController == nil) + NSAssert(NO, @"ShareKit: There is no view controller to display from"); + + + // If a view is already being shown, hide it, and then try again + if (currentView != nil) + { + self.pendingView = vc; + [[currentView parentViewController] dismissModalViewControllerAnimated:YES]; + return; + } + + // Wrap the view in a nav controller if not already + if (![vc respondsToSelector:@selector(pushViewController:animated:)]) + { + UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:vc] autorelease]; + [topViewController presentModalViewController:nav animated:YES]; + nav.navigationBar.barStyle = + nav.toolbar.barStyle = [SHK barStyle]; + self.currentView = nav; + } + + // Show the nav controller + else + { + [topViewController presentModalViewController:vc animated:YES]; + [(UINavigationController *)vc navigationBar].barStyle = + [(UINavigationController *)vc toolbar].barStyle = [SHK barStyle]; + self.currentView = vc; + } + + self.pendingView = nil; +} + +- (void)hideCurrentViewControllerAnimated:(BOOL)animated +{ + if (isDismissingView) + return; + + if (currentView != nil) + { + // Dismiss the modal view + if ([currentView parentViewController] != nil) + { + self.isDismissingView = YES; + [[currentView parentViewController] dismissModalViewControllerAnimated:animated]; + } + + else + self.currentView = nil; + } +} + +- (void)viewWasDismissed +{ + self.isDismissingView = NO; + + if (currentView != nil) + currentView = nil; + + if (pendingView) + { + [self showViewController:pendingView]; + return; + } +} + +- (UIViewController *)getTopViewController +{ + UIViewController *topViewController = rootViewController; + while (topViewController.modalViewController != nil) + topViewController = topViewController.modalViewController; + return topViewController; +} + ++ (UIBarStyle)barStyle +{ + if ([SHKBarStyle isEqualToString:@"UIBarStyleBlack"]) + return UIBarStyleBlack; + + else if ([SHKBarStyle isEqualToString:@"UIBarStyleBlack"]) + return UIBarStyleBlackOpaque; + + else if ([SHKBarStyle isEqualToString:@"UIBarStyleBlack"]) + return UIBarStyleBlackTranslucent; + + return UIBarStyleDefault; +} + + +#pragma mark - +#pragma mark Favorites + + ++ (NSArray *)favoriteSharersForType:(SHKShareType)type +{ + NSArray *favoriteSharers = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"%@%i", SHK_FAVS_PREFIX_KEY, type]]; + + // set defaults + if (favoriteSharers == nil) + { + switch (type) + { + case SHKShareTypeURL: + favoriteSharers = [NSArray arrayWithObjects:@"SHKTwitter",@"SHKFacebook",@"SHKReadItLater",nil]; + break; + + case SHKShareTypeImage: + favoriteSharers = [NSArray arrayWithObjects:@"SHKMail",@"SHKFacebook",@"SHKCopy",nil]; + break; + + case SHKShareTypeText: + favoriteSharers = [NSArray arrayWithObjects:@"SHKMail",@"SHKTwitter", nil]; + break; + + case SHKShareTypeFile: + favoriteSharers = [NSArray arrayWithObjects:@"SHKMail", nil]; + break; + } + + // Save defaults to prefs + [self setFavorites:favoriteSharers forType:type]; + } + + return favoriteSharers; +} + ++ (void)pushOnFavorites:(NSString *)className forType:(SHKShareType)type +{ + NSMutableArray *favs = [[self favoriteSharersForType:type] mutableCopy]; + + [favs removeObject:className]; + [favs insertObject:className atIndex:0]; + + while (favs.count > SHK_MAX_FAV_COUNT) + [favs removeLastObject]; + + [self setFavorites:favs forType:type]; + + [favs release]; +} + ++ (void)setFavorites:(NSArray *)favs forType:(SHKShareType)type +{ + [[NSUserDefaults standardUserDefaults] setObject:favs forKey:[NSString stringWithFormat:@"%@%i", SHK_FAVS_PREFIX_KEY, type]]; +} + +#pragma mark - + ++ (NSDictionary *)getUserExclusions +{ + return [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"%@Exclusions", SHK_FAVS_PREFIX_KEY]]; +} + ++ (void)setUserExclusions:(NSDictionary *)exclusions +{ + return [[NSUserDefaults standardUserDefaults] setObject:exclusions forKey:[NSString stringWithFormat:@"%@Exclusions", SHK_FAVS_PREFIX_KEY]]; +} + + + +#pragma mark - +#pragma mark Credentials + +#define SHK_AUTH_PREFIX @"SHK_AUTH_" + +// TODO someone with more keychain experience may want to clean this up. The use of SFHFKeychainUtils may be unnecessary bloat? + ++ (NSString *)getAuthValueForKey:(NSString *)key forSharer:(NSString *)sharerId +{ +#if TARGET_IPHONE_SIMULATOR + // Using NSUserDefaults for storage is very insecure, but because Keychain only exists on a device + // we use NSUserDefaults when running on the simulator to store objects. This allows you to still test + // in the simulator. You should NOT modify in a way that does not use keychain when actually deployed to a device. + return [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"%@_%@_%@",SHK_AUTH_PREFIX,sharerId,key]]; +#else + return [SFHFKeychainUtils getPasswordForUsername:key andServiceName:sharerId error:nil]; +#endif +} + ++ (void)setAuthValue:(NSString *)value forKey:(NSString *)key forSharer:(NSString *)sharerId +{ +#if TARGET_IPHONE_SIMULATOR + // Using NSUserDefaults for storage is very insecure, but because Keychain only exists on a device + // we use NSUserDefaults when running on the simulator to store objects. This allows you to still test + // in the simulator. You should NOT modify in a way that does not use keychain when actually deployed to a device. + [[NSUserDefaults standardUserDefaults] setObject:value forKey:[NSString stringWithFormat:@"%@_%@_%@",SHK_AUTH_PREFIX,sharerId,key]]; +#else + [SFHFKeychainUtils storeUsername:key andPassword:value forServiceName:sharerId updateExisting:YES error:nil]; +#endif +} + + +#pragma mark - + +static NSDictionary *sharersDictionary = nil; + ++ (NSDictionary *)sharersDictionary +{ + if (sharersDictionary == nil) + sharersDictionary = [[NSDictionary dictionaryWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"SHKSharers.plist"]] retain]; + + return sharersDictionary; +} + + +#pragma mark - +#pragma mark Offline Support + ++ (NSString *)offlineQueueListPath +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSArray *paths = NSSearchPathForDirectoriesInDomains( NSCachesDirectory, NSUserDomainMask, YES); + NSString *cache = [paths objectAtIndex:0]; + NSString *SHKPath = [cache stringByAppendingPathComponent:@"SHK"]; + NSString *listPath = [SHKPath stringByAppendingPathComponent:@"SHKOfflineQueue.plist"]; + + // Check if the path exists, otherwise create it + if (![fileManager fileExistsAtPath:SHKPath]) + [fileManager createDirectoryAtPath:SHKPath withIntermediateDirectories:YES attributes:nil error:nil]; + + return listPath; +} + ++ (NSMutableArray *)getOfflineQueueList +{ + return [[[NSArray arrayWithContentsOfFile:[self offlineQueueListPath]] mutableCopy] autorelease]; +} + ++ (void)saveOfflineQueueList:(NSMutableArray *)queueList +{ + [queueList writeToFile:[self offlineQueueListPath] atomically:YES]; // TODO - should do this off of the main thread +} + ++ (BOOL)addToOfflineQueue:(SHKItem *)item forSharer:(NSString *)sharerId +{ + // Generate a unique id for the share to use when saving associated files + NSString *uid = [NSString stringWithFormat:@"%@-%i-%i-%i", sharerId, item.shareType, [[NSDate date] timeIntervalSince1970], arc4random()]; + + + // store image in cache + if (item.shareType == SHKShareTypeImage && item.image) + [UIImageJPEGRepresentation(item.image, 100) writeToFile:[[self offlineQueueListPath] stringByAppendingPathComponent:uid] atomically:YES]; + + // store file in cache + else if (item.shareType == SHKShareTypeFile) + [item.data writeToFile:[[self offlineQueueListPath] stringByAppendingPathComponent:uid] atomically:YES]; + + // Open queue list + NSMutableArray *queueList = [self getOfflineQueueList]; + if (queueList == nil) + queueList = [NSMutableArray arrayWithCapacity:0]; + + // Add to queue list + [queueList addObject:[NSDictionary dictionaryWithObjectsAndKeys: + [item dictionaryRepresentation],@"item", + sharerId,@"sharer", + uid,@"uid", + nil]]; + + [self saveOfflineQueueList:queueList]; + + return YES; +} + ++ (void)flushOfflineQueue +{ + // TODO - if an item fails, after all items are shared, it should present a summary view and allow them to see which items failed/succeeded + + // Check for a connection + if (![self connected]) + return; + + // Open list + NSMutableArray *queueList = [self getOfflineQueueList]; + + // Run through each item in the quietly in the background + // TODO - Is this the best behavior? Instead, should the user confirm sending these again? Maybe only if it has been X days since they were saved? + // - want to avoid a user being suprised by a post to Twitter if that happens long after they forgot they even shared it. + if (queueList != nil) + { + SHK *helper = [self currentHelper]; + + if (helper.offlineQueue == nil) + helper.offlineQueue = [[NSOperationQueue alloc] init]; + + SHKItem *item; + NSString *sharerId; + + for (NSDictionary *entry in queueList) + { + item = [SHKItem itemFromDictionary:[entry objectForKey:@"item"]]; + sharerId = [entry objectForKey:@"sharer"]; + + if (item != nil && sharerId != nil) + [helper.offlineQueue addOperation:[[[SHKOfflineSharer alloc] initWithItem:item forSharer:sharerId] autorelease]]; + } + + // Remove offline queue - TODO: only do this if everything was successful? + [[NSFileManager defaultManager] removeItemAtPath:[self offlineQueueListPath] error:nil]; + } +} + +#pragma mark - + ++ (NSError *)error:(NSString *)description, ... +{ + va_list args; + va_start(args, description); + NSString *string = [[[NSString alloc] initWithFormat:description arguments:args] autorelease]; + va_end(args); + + return [NSError errorWithDomain:@"sharekit" code:1 userInfo:[NSDictionary dictionaryWithObject:string forKey:NSLocalizedDescriptionKey]]; +} + +#pragma mark - +#pragma mark Network + ++ (BOOL)connected +{ + Reachability *hostReach = [Reachability reachabilityForInternetConnection]; + NetworkStatus netStatus = [hostReach currentReachabilityStatus]; + return !(netStatus == NotReachable); +} + +@end + + + +NSString * SHKEncode(NSString * value) +{ + if (value == nil) + return @""; + + NSString *string = value; + + string = [string stringByReplacingOccurrencesOfString:@"&" withString:@"&"]; + string = [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + string = [string stringByReplacingOccurrencesOfString:@"&" withString:@"%26"]; + + return string; +} + +NSString * SHKEncodeURL(NSURL * value) +{ + if (value == nil) + return @""; + + NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)value.absoluteString, + NULL, + CFSTR("!*'();:@&=+$,/?%#[]"), + kCFStringEncodingUTF8); + [result autorelease]; + return result; +} diff --git a/Classes/ShareKit/Core/SHKItem.h b/Classes/ShareKit/Core/SHKItem.h new file mode 100644 index 00000000..19064a41 --- /dev/null +++ b/Classes/ShareKit/Core/SHKItem.h @@ -0,0 +1,86 @@ +// +// SHKItem.h +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + +typedef enum +{ + SHKShareTypeUndefined, + SHKShareTypeURL, + SHKShareTypeText, + SHKShareTypeImage, + SHKShareTypeFile +} SHKShareType; + + +@interface SHKItem : NSObject +{ + SHKShareType shareType; + + NSURL *URL; + + UIImage *image; + + NSString *title; + NSString *text; + NSString *tags; + + NSData *data; + NSString *mimeType; + NSString *filename; + + @private + NSMutableDictionary *custom; +} + +@property (nonatomic) SHKShareType shareType; + +@property (nonatomic, retain) NSURL *URL; + +@property (nonatomic, retain) UIImage *image; + +@property (nonatomic, retain) NSString *title; +@property (nonatomic, retain) NSString *text; +@property (nonatomic, retain) NSString *tags; + +@property (nonatomic, retain) NSData *data; +@property (nonatomic, retain) NSString *mimeType; +@property (nonatomic, retain) NSString *filename; + ++ (SHKItem *)URL:(NSURL *)url title:(NSString *)title; ++ (SHKItem *)image:(UIImage *)image title:(NSString *)title; ++ (SHKItem *)text:(NSString *)text; ++ (SHKItem *)file:(NSData *)data filename:(NSString *)filename mimeType:(NSString *)mimeType title:(NSString *)title; + +- (void)setCustomValue:(NSString *)value forKey:(NSString *)key; +- (NSString *)customValueForKey:(NSString *)key; +- (BOOL)customBoolForSwitchKey:(NSString *)key; + +- (NSDictionary *)dictionaryRepresentation; ++ (SHKItem *)itemFromDictionary:(NSDictionary *)dictionary; + +@end diff --git a/Classes/ShareKit/Core/SHKItem.m b/Classes/ShareKit/Core/SHKItem.m new file mode 100644 index 00000000..6216d833 --- /dev/null +++ b/Classes/ShareKit/Core/SHKItem.m @@ -0,0 +1,183 @@ +// +// SHKItem.m +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKItem.h" +#import "SHK.h" + + +@interface SHKItem() +@property (nonatomic, retain) NSMutableDictionary *custom; +@end + + +@implementation SHKItem + +@synthesize shareType; +@synthesize URL, image, title, text, tags, data, mimeType, filename; +@synthesize custom; + +- (void)dealloc +{ + [URL release]; + + [image release]; + + [title release]; + [text release]; + [tags release]; + + [data release]; + [mimeType release]; + [filename release]; + + [custom release]; + + [super dealloc]; +} + + ++ (SHKItem *)URL:(NSURL *)url +{ + return [self URL:url title:nil]; +} + ++ (SHKItem *)URL:(NSURL *)url title:(NSString *)title +{ + SHKItem *item = [[SHKItem alloc] init]; + item.shareType = SHKShareTypeURL; + item.URL = url; + item.title = title; + + return [item autorelease]; +} + ++ (SHKItem *)image:(UIImage *)image +{ + return [SHKItem image:image title:nil]; +} + ++ (SHKItem *)image:(UIImage *)image title:(NSString *)title +{ + SHKItem *item = [[SHKItem alloc] init]; + item.shareType = SHKShareTypeImage; + item.image = image; + item.title = title; + + return [item autorelease]; +} + ++ (SHKItem *)text:(NSString *)text +{ + SHKItem *item = [[SHKItem alloc] init]; + item.shareType = SHKShareTypeText; + item.text = text; + + return [item autorelease]; +} + ++ (SHKItem *)file:(NSData *)data filename:(NSString *)filename mimeType:(NSString *)mimeType title:(NSString *)title +{ + SHKItem *item = [[SHKItem alloc] init]; + item.shareType = SHKShareTypeFile; + item.data = data; + item.filename = filename; + item.mimeType = mimeType; + item.title = title; + + return [item autorelease]; +} + +#pragma mark - + +- (void)setCustomValue:(NSString *)value forKey:(NSString *)key +{ + if (custom == nil) + self.custom = [NSMutableDictionary dictionaryWithCapacity:0]; + + if (value == nil) + [custom removeObjectForKey:key]; + + else + [custom setObject:value forKey:key]; +} + +- (NSString *)customValueForKey:(NSString *)key +{ + return [custom objectForKey:key]; +} + +- (BOOL)customBoolForSwitchKey:(NSString *)key +{ + return [[custom objectForKey:key] isEqualToString:SHKFormFieldSwitchOn]; +} + + +#pragma mark - + ++ (SHKItem *)itemFromDictionary:(NSDictionary *)dictionary +{ + SHKItem *item = [[SHKItem alloc] init]; + item.shareType = [[dictionary objectForKey:@"shareType"] intValue]; + + if ([dictionary objectForKey:@"URL"] != nil) + item.URL = [NSURL URLWithString:[dictionary objectForKey:@"URL"]]; + + item.title = [dictionary objectForKey:@"title"]; + item.text = [dictionary objectForKey:@"text"]; + item.tags = [dictionary objectForKey:@"tags"]; + + if ([dictionary objectForKey:@"custom"] != nil) + item.custom = [[[dictionary objectForKey:@"custom"] mutableCopy] autorelease]; + + return [item autorelease]; +} + +- (NSDictionary *)dictionaryRepresentation +{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:0]; + + [dictionary setObject:[NSNumber numberWithInt:shareType] forKey:@"shareType"]; + [dictionary setObject:custom forKey:@"custom"]; + + if (URL != nil) + [dictionary setObject:[URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:@"URL"]; + + if (title != nil) + [dictionary setObject:title forKey:@"title"]; + + if (text != nil) + [dictionary setObject:text forKey:@"text"]; + + if (tags != nil) + [dictionary setObject:tags forKey:@"tags"]; + + // If you add anymore, make sure to add a method for retrieving them to the itemWithDictionary function too + + return dictionary; +} + +@end diff --git a/Classes/ShareKit/Core/SHKOfflineSharer.h b/Classes/ShareKit/Core/SHKOfflineSharer.h new file mode 100644 index 00000000..1312969e --- /dev/null +++ b/Classes/ShareKit/Core/SHKOfflineSharer.h @@ -0,0 +1,56 @@ +// +// SHKOfflineSharer.h +// ShareKit +// +// Created by Nathan Weiner on 6/22/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHK.h" +#import "SHKSharer.h" + +@interface SHKOfflineSharer : NSOperation +{ + SHKItem *item; + NSString *sharerId; + NSString *uid; + BOOL readyToFinish; + NSThread *runLoopThread; + SHKSharer *sharer; +} + +@property (nonatomic, retain) SHKItem *item; +@property (nonatomic, retain) NSString *sharerId; +@property (nonatomic, retain) NSString *uid; +@property BOOL readyToFinish; +@property (nonatomic, retain) NSThread *runLoopThread; +@property (nonatomic, retain) SHKSharer *sharer; + +- (id)initWithItem:(SHKItem *)i forSharer:(NSString *)s; + +- (void)share; +- (BOOL)shouldRun; +- (void)finish; +- (void)lastSpin; + +@end diff --git a/Classes/ShareKit/Core/SHKOfflineSharer.m b/Classes/ShareKit/Core/SHKOfflineSharer.m new file mode 100644 index 00000000..5273416d --- /dev/null +++ b/Classes/ShareKit/Core/SHKOfflineSharer.m @@ -0,0 +1,153 @@ +// +// SHKOfflineSharer.m +// ShareKit +// +// Created by Nathan Weiner on 6/22/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKOfflineSharer.h" +#import "SHKSharer.h" + +@implementation SHKOfflineSharer + +@synthesize item, sharerId, uid; +@synthesize readyToFinish; +@synthesize runLoopThread; +@synthesize sharer; + +- (void)dealloc +{ + [item release]; + [sharerId release]; + [uid release]; + [runLoopThread release]; + [sharer release]; + [super dealloc]; +} + +- (id)initWithItem:(SHKItem *)i forSharer:(NSString *)s +{ + if (self = [super init]) + { + self.item = i; + self.sharerId = s; + } + return self; +} + +- (void)main +{ + // Make sure it hasn't been cancelled + if (![self shouldRun]) + return; + + // Save the thread so we can spin up the run loop later + self.runLoopThread = [NSThread currentThread]; + + // Run actual sharing on the main thread to avoid thread issues + [self performSelectorOnMainThread:@selector(share) withObject:nil waitUntilDone:YES]; + + // Keep the operation alive while we perform the send async + // This way only one will run at a time + while([self shouldRun]) + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; +} + +- (void)share +{ + // create sharer + self.sharer = [[NSClassFromString(sharerId) alloc] init]; + sharer.item = item; + sharer.quiet = YES; + sharer.shareDelegate = self; + + if (![sharer isAuthorized]) + { + [self finish]; + return; + } + + // reload image from disk and remove the file + NSString *path; + if (item.shareType == SHKShareTypeImage) + { + path = [[SHK offlineQueueListPath] stringByAppendingPathComponent:uid]; + sharer.item.image = [UIImage imageWithContentsOfFile:path]; + [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + } + + // reload file from disk and remove the file + else if (item.shareType == SHKShareTypeFile) + { + path = [[SHK offlineQueueListPath] stringByAppendingPathComponent:uid]; + sharer.item.data = [NSData dataWithContentsOfFile:[[SHK offlineQueueListPath] stringByAppendingPathComponent:uid]]; + [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + } + + [sharer tryToSend]; + [sharer release]; +} + +- (BOOL)shouldRun +{ + return ![self isCancelled] && ![self isFinished] && !readyToFinish; +} + +- (void)finish +{ + self.readyToFinish = YES; + [self performSelector:@selector(lastSpin) onThread:runLoopThread withObject:nil waitUntilDone:NO]; +} + +- (void)lastSpin +{ + // Just used to make the run loop spin +} + +#pragma mark - +#pragma mark SHKSharerDelegate + +- (void)sharerStartedSending:(SHKSharer *)aSharer +{ + +} + +- (void)sharerFinishedSending:(SHKSharer *)aSharer +{ + sharer.shareDelegate = nil; + [self finish]; +} + +- (void)sharer:(SHKSharer *)aSharer failedWithError:(NSError *)error shouldRelogin:(BOOL)shouldRelogin +{ + sharer.shareDelegate = nil; + [self finish]; +} + +- (void)sharerCancelledSending:(SHKSharer *)aSharer +{ + sharer.shareDelegate = nil; + [self finish]; +} + +@end diff --git a/Classes/ShareKit/Core/SHKSharers.plist b/Classes/ShareKit/Core/SHKSharers.plist new file mode 100644 index 00000000..0d20aac9 --- /dev/null +++ b/Classes/ShareKit/Core/SHKSharers.plist @@ -0,0 +1,21 @@ + + + + + actions + + SHKCopy + SHKMail + SHKSafari + + services + + SHKTwitter + SHKPinboard + SHKDelicious + SHKGoogleReader + SHKFacebook + SHKReadItLater + + + diff --git a/Classes/ShareKit/Customize UI/SHKCustomFormController.h b/Classes/ShareKit/Customize UI/SHKCustomFormController.h new file mode 100644 index 00000000..f93e0280 --- /dev/null +++ b/Classes/ShareKit/Customize UI/SHKCustomFormController.h @@ -0,0 +1,35 @@ +// +// SHKCustomFormController.h +// ShareKit +// +// Created by Nathan Weiner on 6/28/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKFormController.h" + +@interface SHKCustomFormController : SHKFormController { + +} + +@end diff --git a/Classes/ShareKit/Customize UI/SHKCustomFormController.m b/Classes/ShareKit/Customize UI/SHKCustomFormController.m new file mode 100644 index 00000000..9ed82a18 --- /dev/null +++ b/Classes/ShareKit/Customize UI/SHKCustomFormController.m @@ -0,0 +1,133 @@ +// +// SHKCustomFormController.m +// ShareKit +// +// Created by Nathan Weiner on 6/28/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKCustomFormController.h" + + +@implementation SHKCustomFormController + +// See http://getsharekit.com/customize/ for additional information on customizing +/* +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // Change the background color to something yellow/paperishy + self.tableView.backgroundColor = [UIColor colorWithRed:233.0/255.0 + green:231.0/255.0 + blue:214.0/255.0 + alpha:1]; + + // Change the cell border color to match + self.tableView.separatorColor = [UIColor colorWithRed:207.0/255.0 + green:204.0/255.0 + blue:199.0/255.0 + alpha:1]; + +} + +// Customize the look of the cell +- (UITableViewCell *)tableView:(UITableView *)tableView + cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + SHKCustomFormFieldCell *cell = + (SHKCustomFormFieldCell *)[super tableView:tableView + cellForRowAtIndexPath:indexPath]; + + // lighter color + cell.textLabel.textColor = [UIColor lightGrayColor]; + + // smaller font + cell.textLabel.font = [UIFont boldSystemFontOfSize:13]; + + // more subtle cell background + cell.backgroundColor = [UIColor colorWithRed:234.0/255.0 + green:234.0/255.0 + blue:234.0/255.0 + alpha:1]; + + return cell; +} + +// Create a custom footer label so we can style it +- (UIView *)tableView:(UITableView *)tableView + viewForFooterInSection:(NSInteger)section +{ + NSString *footerTitle = [self tableView:tableView titleForFooterInSection:section]; + if (footerTitle != nil) + { + // Create a view to put the label in so we have some padding + UIView *wrapper = [[[UIView alloc] + initWithFrame:CGRectMake(0, + 0, + tableView.frame.size.width, + 50)] autorelease]; + wrapper.autoresizesSubviews = YES; + wrapper.autoresizingMask = UIViewAutoresizingFlexibleWidth; + + // Create the label + CGRect labelFrame = CGRectMake( + round(tableView.frame.size.width/2-300/2), + 0, + 300, + 50); + UILabel *label = [[[UILabel alloc] initWithFrame:labelFrame] autorelease]; + label.backgroundColor = [UIColor clearColor]; + label.opaque = NO; + label.textColor = [UIColor grayColor]; + label.font = [UIFont systemFontOfSize:13]; + + label.textAlignment = UITextAlignmentCenter; + label.lineBreakMode = UILineBreakModeWordWrap; + label.numberOfLines = 0; + + label.text = footerTitle; + + label.autoresizesSubviews = YES; + label.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | + UIViewAutoresizingFlexibleRightMargin; + + [wrapper addSubview:label]; + + return wrapper; + } + + return nil; +} + +// Set the height of our label (when we have one to display) +- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section +{ + NSString *footerTitle = [self tableView:tableView titleForFooterInSection:section]; + if (footerTitle != nil) + return 50; + + return 0; +} +*/ + +@end diff --git a/Classes/ShareKit/Customize UI/SHKCustomFormFieldCell.h b/Classes/ShareKit/Customize UI/SHKCustomFormFieldCell.h new file mode 100644 index 00000000..37c34a97 --- /dev/null +++ b/Classes/ShareKit/Customize UI/SHKCustomFormFieldCell.h @@ -0,0 +1,36 @@ +// +// SHKCustomFormFieldCell.h +// ShareKit +// +// Created by Nathan Weiner on 6/28/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKFormFieldCell.h" + +@interface SHKCustomFormFieldCell : SHKFormFieldCell +{ + +} + +@end diff --git a/Classes/ShareKit/Customize UI/SHKCustomFormFieldCell.m b/Classes/ShareKit/Customize UI/SHKCustomFormFieldCell.m new file mode 100644 index 00000000..a72d76e3 --- /dev/null +++ b/Classes/ShareKit/Customize UI/SHKCustomFormFieldCell.m @@ -0,0 +1,35 @@ +// +// SHKCustomFormFieldCell.m +// ShareKit +// +// Created by Nathan Weiner on 6/28/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKCustomFormFieldCell.h" + + +@implementation SHKCustomFormFieldCell + +// See http://getsharekit.com/customize/ for additional information on customizing + +@end diff --git a/Classes/ShareKit/Customize UI/SHKCustomShareMenu.h b/Classes/ShareKit/Customize UI/SHKCustomShareMenu.h new file mode 100644 index 00000000..6328077f --- /dev/null +++ b/Classes/ShareKit/Customize UI/SHKCustomShareMenu.h @@ -0,0 +1,40 @@ +// +// SHKCustomShareMenu.h +// RIL +// +// Created by Nathan Weiner on 6/30/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKShareMenu.h" + + + +@interface SHKCustomShareMenu : SHKShareMenu +{ + // See http://getsharekit.com/customize/ for additional information on customizing +} + + + +@end diff --git a/Classes/ShareKit/Customize UI/SHKCustomShareMenu.m b/Classes/ShareKit/Customize UI/SHKCustomShareMenu.m new file mode 100644 index 00000000..aa6edec0 --- /dev/null +++ b/Classes/ShareKit/Customize UI/SHKCustomShareMenu.m @@ -0,0 +1,36 @@ +// +// SHKCustomShareMenu.m +// RIL +// +// Created by Nathan Weiner on 6/30/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKCustomShareMenu.h" + +@implementation SHKCustomShareMenu + + +// See http://getsharekit.com/customize/ for additional information on customizing + + +@end diff --git a/Classes/ShareKit/Customize UI/SHKCustomShareMenuCell.h b/Classes/ShareKit/Customize UI/SHKCustomShareMenuCell.h new file mode 100644 index 00000000..5b226131 --- /dev/null +++ b/Classes/ShareKit/Customize UI/SHKCustomShareMenuCell.h @@ -0,0 +1,45 @@ +// +// SHKTableViewCell.h +// RIL +// +// Created by Nathan Weiner on 6/30/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +/* + Two ways to customize: + + 1. If you already have a custom UITableViewCell subclass you are using in your app, + simply replace UITableViewCell with your own class. + + 2. Add any customizations by subclassing this (SHKTableViewCell) +*/ + +@interface SHKCustomShareMenuCell : UITableViewCell +{ + // See http://getsharekit.com/customize/ for additional information on customizing +} + +@end diff --git a/Classes/ShareKit/Customize UI/SHKCustomShareMenuCell.m b/Classes/ShareKit/Customize UI/SHKCustomShareMenuCell.m new file mode 100644 index 00000000..cd31fba3 --- /dev/null +++ b/Classes/ShareKit/Customize UI/SHKCustomShareMenuCell.m @@ -0,0 +1,35 @@ +// +// SHKTableViewCell.m +// RIL +// +// Created by Nathan Weiner on 6/30/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKCustomShareMenuCell.h" + + +@implementation SHKCustomShareMenuCell + +// See http://getsharekit.com/customize/ for additional information on customizing + +@end diff --git a/Classes/ShareKit/Reachability/Reachability.h b/Classes/ShareKit/Reachability/Reachability.h new file mode 100644 index 00000000..1f72d45a --- /dev/null +++ b/Classes/ShareKit/Reachability/Reachability.h @@ -0,0 +1,88 @@ +/* + + File: Reachability.h + Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + + Version: 2.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under + Apple's copyrights in this original Apple software (the "Apple Software"), to + use, reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions + of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may be used + to endorse or promote products derived from the Apple Software without specific + prior written permission from Apple. Except as expressly stated in this notice, + no other rights or licenses, express or implied, are granted by Apple herein, + including but not limited to any patent rights that may be infringed by your + derivative works or by other works in which the Apple Software may be + incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR + DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF + CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF + APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2010 Apple Inc. All Rights Reserved. + +*/ + + +#import +#import + +typedef enum { + NotReachable = 0, + ReachableViaWiFi, + ReachableViaWWAN +} NetworkStatus; +#define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification" + +@interface Reachability: NSObject +{ + BOOL localWiFiRef; + SCNetworkReachabilityRef reachabilityRef; +} + +//reachabilityWithHostName- Use to check the reachability of a particular host name. ++ (Reachability*) reachabilityWithHostName: (NSString*) hostName; + +//reachabilityWithAddress- Use to check the reachability of a particular IP address. ++ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress; + +//reachabilityForInternetConnection- checks whether the default route is available. +// Should be used by applications that do not connect to a particular host ++ (Reachability*) reachabilityForInternetConnection; + +//reachabilityForLocalWiFi- checks whether a local wifi connection is available. ++ (Reachability*) reachabilityForLocalWiFi; + +//Start listening for reachability notifications on the current run loop +- (BOOL) startNotifier; +- (void) stopNotifier; + +- (NetworkStatus) currentReachabilityStatus; +//WWAN may be available, but not active until a connection has been established. +//WiFi may require a connection for VPN on Demand. +- (BOOL) connectionRequired; +@end + + diff --git a/Classes/ShareKit/Reachability/Reachability.m b/Classes/ShareKit/Reachability/Reachability.m new file mode 100644 index 00000000..a7f69abd --- /dev/null +++ b/Classes/ShareKit/Reachability/Reachability.m @@ -0,0 +1,273 @@ +/* + + File: Reachability.m + Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs. + + Version: 2.1 + + Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. + ("Apple") in consideration of your agreement to the following terms, and your + use, installation, modification or redistribution of this Apple software + constitutes acceptance of these terms. If you do not agree with these terms, + please do not use, install, modify or redistribute this Apple software. + + In consideration of your agreement to abide by the following terms, and subject + to these terms, Apple grants you a personal, non-exclusive license, under + Apple's copyrights in this original Apple software (the "Apple Software"), to + use, reproduce, modify and redistribute the Apple Software, with or without + modifications, in source and/or binary forms; provided that if you redistribute + the Apple Software in its entirety and without modifications, you must retain + this notice and the following text and disclaimers in all such redistributions + of the Apple Software. + Neither the name, trademarks, service marks or logos of Apple Inc. may be used + to endorse or promote products derived from the Apple Software without specific + prior written permission from Apple. Except as expressly stated in this notice, + no other rights or licenses, express or implied, are granted by Apple herein, + including but not limited to any patent rights that may be infringed by your + derivative works or by other works in which the Apple Software may be + incorporated. + + The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + COMBINATION WITH YOUR PRODUCTS. + + IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR + DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF + CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF + APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Copyright (C) 2010 Apple Inc. All Rights Reserved. + +*/ + +#import +#import +#import +#import +#import +#import + +#import + +#import "Reachability.h" + +#define kShouldPrintReachabilityFlags 0 + +static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment) +{ +#if kShouldPrintReachabilityFlags + + NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n", + (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', + (flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-', + + (flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-', + (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-', + (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', + (flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-', + (flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-', + comment + ); +#endif +} + + +@implementation Reachability +static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) +{ + #pragma unused (target, flags) + NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback"); + NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback"); + + //We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively + // in case someon uses the Reachablity object in a different thread. + NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init]; + + Reachability* noteObject = (Reachability*) info; + // Post a notification to notify the client that the network reachability changed. + [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject]; + + [myPool release]; +} + +- (BOOL) startNotifier +{ + BOOL retVal = NO; + SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL}; + if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) + { + if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) + { + retVal = YES; + } + } + return retVal; +} + +- (void) stopNotifier +{ + if(reachabilityRef!= NULL) + { + SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + } +} + +- (void) dealloc +{ + [self stopNotifier]; + if(reachabilityRef!= NULL) + { + CFRelease(reachabilityRef); + } + [super dealloc]; +} + ++ (Reachability*) reachabilityWithHostName: (NSString*) hostName; +{ + Reachability* retVal = NULL; + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]); + if(reachability!= NULL) + { + retVal= [[[self alloc] init] autorelease]; + if(retVal!= NULL) + { + retVal->reachabilityRef = reachability; + retVal->localWiFiRef = NO; + } + } + return retVal; +} + ++ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress; +{ + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); + Reachability* retVal = NULL; + if(reachability!= NULL) + { + retVal= [[[self alloc] init] autorelease]; + if(retVal!= NULL) + { + retVal->reachabilityRef = reachability; + retVal->localWiFiRef = NO; + } + } + return retVal; +} + ++ (Reachability*) reachabilityForInternetConnection; +{ + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + return [self reachabilityWithAddress: &zeroAddress]; +} + ++ (Reachability*) reachabilityForLocalWiFi; +{ + struct sockaddr_in localWifiAddress; + bzero(&localWifiAddress, sizeof(localWifiAddress)); + localWifiAddress.sin_len = sizeof(localWifiAddress); + localWifiAddress.sin_family = AF_INET; + // IN_LINKLOCALNETNUM is defined in as 169.254.0.0 + localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); + Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress]; + if(retVal!= NULL) + { + retVal->localWiFiRef = YES; + } + return retVal; +} + +#pragma mark Network Flag Handling + +- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags +{ + PrintReachabilityFlags(flags, "localWiFiStatusForFlags"); + + BOOL retVal = NotReachable; + if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) + { + retVal = ReachableViaWiFi; + } + return retVal; +} + +- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags +{ + PrintReachabilityFlags(flags, "networkStatusForFlags"); + if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) + { + // if target host is not reachable + return NotReachable; + } + + BOOL retVal = NotReachable; + + if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) + { + // if target host is reachable and no connection is required + // then we'll assume (for now) that your on Wi-Fi + retVal = ReachableViaWiFi; + } + + + if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) + { + // ... and the connection is on-demand (or on-traffic) if the + // calling application is using the CFSocketStream or higher APIs + + if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) + { + // ... and no [user] intervention is needed + retVal = ReachableViaWiFi; + } + } + + if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) + { + // ... but WWAN connections are OK if the calling application + // is using the CFNetwork (CFSocketStream?) APIs. + retVal = ReachableViaWWAN; + } + return retVal; +} + +- (BOOL) connectionRequired; +{ + NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef"); + SCNetworkReachabilityFlags flags; + if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + return (flags & kSCNetworkReachabilityFlagsConnectionRequired); + } + return NO; +} + +- (NetworkStatus) currentReachabilityStatus +{ + NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef"); + NetworkStatus retVal = NotReachable; + SCNetworkReachabilityFlags flags; + if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) + { + if(localWiFiRef) + { + retVal = [self localWiFiStatusForFlags: flags]; + } + else + { + retVal = [self networkStatusForFlags: flags]; + } + } + return retVal; +} +@end diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h new file mode 100644 index 00000000..1976afc4 --- /dev/null +++ b/Classes/ShareKit/SHKConfig.h @@ -0,0 +1,127 @@ +// +// SHKConfig.h +// ShareKit +// +// Created by Nathan Weiner on 6/23/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + + +#error Setup the SHKConfig.h file, then remove this error by commenting it out. + + +// App Description +// These values are used by any service that shows 'shared from XYZ' + +#define SHKMyAppName @"My App Name" +#define SHKMyAppURL @"http://example.com" + + + +/* +API Keys +-------- +This is the longest step to getting set up, it involves filling in API keys for the supported services. +It should be pretty painless though and should hopefully take no more than a few minutes. + +Each key below as a link to a page where you can generate an api key. Fill in the key for each service below. + +A note on services you don't need: +If, for example, your app only shares URLs then you probably won't need image services like Flickr. +In these cases it is safe to leave an API key blank. + +However, it is STRONGLY recommended that you do your best to support all services for the types of sharing you support. +The core principle behind ShareKit is to leave the service choices up to the user. Thus, you should not remove any services, +leaving that decision up to the user. +*/ + + + +// Delicious - https://developer.apps.yahoo.com/projects +#define SHKDeliciousConsumerKey @"" +#define SHKDeliciousSecretKey @"" +#define SHKDeliciousCallbackUrl @"" + +// Facebook - http://www.facebook.com/developers +#define SHKFacebookKey @"" +#define SHKFacebookSecret @"" + +// Flickr + +// Read It Later - http://readitlaterlist.com/api/ +#define SHKReadItLaterKey @"" + +// Twitter - http://dev.twitter.com/apps/new +#define SHKTwitterConsumerKey @"" +#define SHKTwitterSecret @"" +#define SHKTwitterCallbackUrl @"" // HOW-TO: In your Twitter application settings, use the "Callback URL" field. If you do not have this field in the settings, set your application type to 'Browser'. +#define SHKTwitterUseXAuth 0 // To use xAuth, set to 1 +#define SHKTwitterUsername @"" // Enter your app's twitter account if you'd like to ask the user to follow it when logging in. (Only for xAuth) + +// Bit.ly (for shortening URLs on Twitter) - http://bit.ly/account/register - after signup: http://bit.ly/a/your_api_key +#define SHKBitLyLogin @"" +#define SHKBitLyKey @"" + + + + +/* + UI Configuration : Basic + ------ + These provide controls for basic UI settings. For more advanced configuration see below. + */ + +// Toolbars +#define SHKBarStyle @"UIBarStyleDefault" // See: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIKitDataTypesReference/Reference/reference.html#//apple_ref/c/econst/UIBarStyleDefault +#define SHKBarTintColorRed -1 // Value between 0-255, set all to -1 for default +#define SHKBarTintColorGreen -1 // Value between 0-255, set all to -1 for default +#define SHKBarTintColorBlue -1 // Value between 0-255, set all to -1 for default + +// Forms +#define SHKFormFontColorRed -1 // Value between 0-255, set all to -1 for default +#define SHKFormFontColorGreen -1 // Value between 0-255, set all to -1 for default +#define SHKFormFontColorBlue -1 // Value between 0-255, set all to -1 for default + +#define SHKFormBgColorRed -1 // Value between 0-255, set all to -1 for default +#define SHKFormBgColorGreen -1 // Value between 0-255, set all to -1 for default +#define SHKFormBgColorBlue -1 // Value between 0-255, set all to -1 for default + + +/* + UI Configuration : Advanced + ------ + If you'd like to do more advanced customization of the ShareKit UI, like background images and more, + check out http://getsharekit.com/customize + */ + + + + +/* + Advanced Configuration + ------ + These settings can be left as is. This only need to be changed for uber custom installs. + */ + +#define SHK_MAX_FAV_COUNT 4 +#define SHK_FAVS_PREFIX_KEY @"SHK_FAVS_" +#define SHK_AUTH_PREFIX @"SHK_AUTH_" \ No newline at end of file diff --git a/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.h b/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.h new file mode 100644 index 00000000..857f5810 --- /dev/null +++ b/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.h @@ -0,0 +1,36 @@ +// +// SHKCopy.h +// ShareKit +// +// Created by Nathan Weiner on 6/20/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" + +@interface SHKCopy : SHKSharer +{ + +} + +@end diff --git a/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m b/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m new file mode 100644 index 00000000..15b92a0f --- /dev/null +++ b/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m @@ -0,0 +1,88 @@ +// +// SHKCopy.m +// ShareKit +// +// Created by Nathan Weiner on 6/20/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKCopy.h" + + +@implementation SHKCopy + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Copy"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + ++ (BOOL)canShareImage +{ + return YES; +} + ++ (BOOL)shareRequiresInternetConnection +{ + return NO; +} + ++ (BOOL)requiresAuthentication +{ + return NO; +} + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + +- (BOOL)shouldAutoShare +{ + return YES; +} + + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send +{ + if (item.shareType == SHKShareTypeURL) + [[UIPasteboard generalPasteboard] setString:item.URL.absoluteString]; + + else + [[UIPasteboard generalPasteboard] setImage:item.image]; + + // Notify user + [[SHKActivityIndicator currentIndicator] displayCompleted:@"Copied!"]; + + return YES; +} + +@end diff --git a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.h b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.h new file mode 100644 index 00000000..88f9bbe7 --- /dev/null +++ b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.h @@ -0,0 +1,46 @@ +// +// SHKMail.h +// ShareKit +// +// Created by Nathan Weiner on 6/17/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" +#import + +@interface SHKMail : SHKSharer +{ + +} + ++ (id)mail:(NSString *)body + subject:(NSString *)subject + to:(NSArray *)to + cc:(NSArray *)cc + bcc:(NSArray *)bcc + attachment:(NSData *)attachment +attachmentMimeType:(NSString *)mimeType +attachmentFileName:(NSString *)filename; + +@end diff --git a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m new file mode 100644 index 00000000..b4117e51 --- /dev/null +++ b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m @@ -0,0 +1,186 @@ +// +// SHKMail.m +// ShareKit +// +// Created by Nathan Weiner on 6/17/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKMail.h" + + +@implementation MFMailComposeViewController (SHK) + +- (void)SHKviewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + // Remove the SHK view wrapper from the window + [[SHK currentHelper] viewWasDismissed]; +} + +@end + + + +@implementation SHKMail + +#import +void SHKSwizzle(Class c, SEL orig, SEL new) +{ + Method origMethod = class_getInstanceMethod(c, orig); + Method newMethod = class_getInstanceMethod(c, new); + if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) + class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); + else + method_exchangeImplementations(origMethod, newMethod); +} + ++ (void)initialize +{ + SHKSwizzle([MFMailComposeViewController class], @selector(viewDidDisappear:), @selector(SHKviewDidDisappear:)); +} + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Email"; +} + ++ (BOOL)canShareText +{ + return YES; +} + ++ (BOOL)canShareURL +{ + return YES; +} + ++ (BOOL)canShareImage +{ + return YES; +} + ++ (BOOL)canShareFile +{ + return YES; +} + ++ (BOOL)shareRequiresInternetConnection +{ + return NO; +} + ++ (BOOL)requiresAuthentication +{ + return NO; +} + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + ++ (BOOL)canShare +{ + return [MFMailComposeViewController canSendMail]; +} + +- (BOOL)shouldAutoShare +{ + return YES; +} + + +#pragma mark - +#pragma mark Share Types + ++ (id)shareURL:(NSURL *)url +{ + return [self shareURL:url title:nil]; +} + ++ (id)shareURL:(NSURL *)url title:(NSString *)title +{ + return [self mail:url.absoluteString subject:title to:nil cc:nil bcc:nil attachment:nil attachmentMimeType:nil attachmentFileName:nil]; +} + ++ (id)shareImage:(UIImage *)image title:(NSString *)title +{ + return [self mail:nil subject:title to:nil cc:nil bcc:nil attachment:UIImageJPEGRepresentation(image, 1) attachmentMimeType:@"image/jpeg" attachmentFileName:@"Image.jpg"]; +} + ++ (id)shareText:(NSString *)text +{ + return [self mail:text subject:nil to:nil cc:nil bcc:nil attachment:nil attachmentMimeType:nil attachmentFileName:nil]; +} + ++ (id)shareFile:(NSData *)file filename:(NSString *)filename mimeType:(NSString *)mimeType title:(NSString *)title +{ + return [self mail:[NSString stringWithFormat:@"Attached: %@", title] + subject:filename to:nil cc:nil bcc:nil + attachment:file attachmentMimeType:mimeType attachmentFileName:filename]; +} + + + + +#pragma mark - +#pragma mark Share API Methods + ++ (id)mail:(NSString *)body + subject:(NSString *)subject + to:(NSArray *)to + cc:(NSArray *)cc + bcc:(NSArray *)bcc + attachment:(NSData *)attachment +attachmentMimeType:(NSString *)mimeType +attachmentFileName:(NSString *)filename +{ + MFMailComposeViewController *mailController = [[[MFMailComposeViewController alloc] init] autorelease]; + mailController.mailComposeDelegate = [[[self alloc] init] autorelease]; + + [mailController setSubject:subject]; + [mailController setMessageBody:body isHTML:YES]; + + [mailController setToRecipients:to]; + [mailController setCcRecipients:cc]; + [mailController setBccRecipients:bcc]; + + if (attachment) + [mailController addAttachmentData:attachment mimeType:mimeType fileName:filename]; + + // How to allow devs to attach present the view how they want o + [[SHK currentHelper] showViewController:mailController]; + + return mailController; +} + +- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error +{ + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; +} + + +@end diff --git a/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.h b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.h new file mode 100644 index 00000000..96cd16fd --- /dev/null +++ b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.h @@ -0,0 +1,36 @@ +// +// SHKSafari.h +// ShareKit +// +// Created by Nathan Weiner on 6/20/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" + +@interface SHKSafari : SHKSharer +{ + +} + +@end diff --git a/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m new file mode 100644 index 00000000..2e269d44 --- /dev/null +++ b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m @@ -0,0 +1,79 @@ +// +// SHKSafari.m +// ShareKit +// +// Created by Nathan Weiner on 6/20/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKSafari.h" + + +@implementation SHKSafari + + + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Open in Safari"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + ++ (BOOL)shareRequiresInternetConnection +{ + return NO; +} + ++ (BOOL)requiresAuthentication +{ + return NO; +} + + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + +- (BOOL)shouldAutoShare +{ + return YES; +} + + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send +{ + [[UIApplication sharedApplication] openURL:item.URL]; + + return YES; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.h b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.h new file mode 100644 index 00000000..9d71d47c --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.h @@ -0,0 +1,41 @@ +// +// SHKDelicious.h +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKOAuthSharer.h" + +@interface SHKDelicious : SHKOAuthSharer +{ + +} + +- (BOOL)handleResponse:(SHKRequest *)aRequest; + +- (void)sendTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data; +- (void)sendTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m new file mode 100644 index 00000000..eb030834 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m @@ -0,0 +1,193 @@ +// +// SHKDelicious.m +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKDelicious.h" +#import "OAuthConsumer.h" + +@implementation SHKDelicious + + +- (id)init +{ + if (self = [super init]) + { + self.consumerKey = SHKDeliciousConsumerKey; + self.secretKey = SHKDeliciousSecretKey; + self.authorizeCallbackURL = [NSURL URLWithString:SHKDeliciousCallbackUrl];// HOW-TO: In your Twitter application settings, use the "Callback URL" field. If you do not have this field in the settings, set your application type to 'Browser'. + + + // -- // + + + // You do not need to edit these, they are the same for everyone + self.authorizeURL = [NSURL URLWithString:@"https://api.login.yahoo.com/oauth/v2/request_auth"]; + self.requestURL = [NSURL URLWithString:@"https://api.login.yahoo.com/oauth/v2/get_request_token"]; + self.accessURL = [NSURL URLWithString:@"https://api.login.yahoo.com/oauth/v2/get_token"]; + + self.signatureProvider = [[[OAPlaintextSignatureProvider alloc] init] autorelease]; + } + return self; +} + + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Delicious"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + + +#pragma mark - +#pragma mark Authentication + +- (void)tokenRequestModifyRequest:(OAMutableURLRequest *)oRequest +{ + [oRequest setOAuthParameterName:@"oauth_callback" withValue:authorizeCallbackURL.absoluteString]; +} + +- (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest +{ + [oRequest setOAuthParameterName:@"oauth_verifier" withValue:[authorizeResponseQueryVars objectForKey:@"oauth_verifier"]]; +} + +- (BOOL)handleResponse:(SHKRequest *)aRequest +{ + NSString *response = [aRequest getResult]; + + if ([response isEqualToString:@"401 Forbidden"]) + { + [self sendDidFailShouldRelogin]; + return NO; + } + + return YES; +} + + +#pragma mark - +#pragma mark Share Form + +- (NSArray *)shareFormFieldsForType:(SHKShareType)type +{ + if (type == SHKShareTypeURL) + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Title" key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:@"Tags" key:@"tags" type:SHKFormFieldTypeText start:item.tags], + [SHKFormFieldSettings label:@"Notes" key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:@"Shared" key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + nil]; + + return nil; +} + + + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send +{ + if ([self validateItem]) + { + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.del.icio.us/v2/posts/add"] + consumer:consumer + token:accessToken + realm:nil + signatureProvider:nil]; + + [oRequest setHTTPMethod:@"GET"]; + + OARequestParameter *urlParam = [[OARequestParameter alloc] initWithName:@"url" + value:SHKEncodeURL(item.URL)]; + + OARequestParameter *descParam = [[OARequestParameter alloc] initWithName:@"description" + value:SHKEncode(item.title)]; + + OARequestParameter *tagsParam = [[OARequestParameter alloc] initWithName:@"tags" + value:SHKEncode(item.tags)]; + + OARequestParameter *extendedParam = [[OARequestParameter alloc] initWithName:@"extended" + value:SHKEncode(item.text)]; + + OARequestParameter *sharedParam = [[OARequestParameter alloc] initWithName:@"shared" + value:[item customBoolForSwitchKey:@"shared"]?@"yes":@"no"]; + + + [oRequest setParameters:[NSArray arrayWithObjects:descParam, extendedParam, sharedParam, tagsParam, urlParam, nil]]; + [urlParam release]; + [descParam release]; + [tagsParam release]; + [extendedParam release]; + [sharedParam release]; + + OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest + delegate:self + didFinishSelector:@selector(sendTicket:didFinishWithData:) + didFailSelector:@selector(sendTicket:didFailWithError:)]; + + [fetcher start]; + [oRequest release]; + + // Notify delegate + [self sendDidStart]; + + return YES; + } + + return NO; +} + +- (void)sendTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data +{ + if (ticket.didSucceed && [ticket.body rangeOfString:@"\"done\""].location != NSNotFound) + { + // Do anything? + } + + else + // TODO - better error handling + [self sendTicket:ticket didFailWithError:[SHK error:@"There was a problem saving to Delicious"]]; + + // Notify delegate + [self sendDidFinish]; +} + +- (void)sendTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error +{ + [self sendDidFailWithError:error]; +} + + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/close.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..a89b82faba7910c645fd1ae8cc285c3e86a0763d GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)H!3HEvS)PI@$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1GZk{fVAr-fhV)i{gR?nu;Q4pS<($FMoo!@kH#s$^{6Apua z|NqOoGO#(Q87`FWJd>VufO*D+w~mDZn^<;r&%B^IL6m_-f}!-QYBk%O&IF)|44$rj JF6*2UngF8LG#3B> literal 0 HcmV?d00001 diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/fbicon.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/fbicon.png new file mode 100644 index 0000000000000000000000000000000000000000..413396be6b5baaaf363d4aa1111e4935c234a1b9 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1SBVD?P>#3k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XT0C7GLn>}1`K*a4etl4y&B?*nv87X@)PW)7Sd+J3Xxxt7 zXM$ZONT1l&Ig3+eW`Snw>SpFS%amrbGy3qjFzYOni=5VXtZhcG>&w~S;~(-hY$%*1 zHDNDHo?MIXrfAQPV&dwv+a^iqWh&=Nay&k^H+;zqE#-6N?_LS}a6UQEt|H#Rz|0U9 Wr}l!o#w8Z$9tKZWKbLh*2~7ZwZcbkS literal 0 HcmV?d00001 diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login.png new file mode 100644 index 0000000000000000000000000000000000000000..77bc30c27400597b79ccc126fabd5bcc0fb3a41c GIT binary patch literal 2102 zcmV-62+8+}P)*hL`sNJ)3hS3TI$f|ffT8Va8oI?La8WKP?HeL zfgrVN3wB7sCK%HYY-)q;wY{wO{haB!cOPDx-Sq=ks;W8Y*uMAdJ#*(f-<)&qumVQK zM5-ngNriE$$iyO#Q;9T0>OumDW(II|b@f_{#qzu;iYsWWRj``|+OlkwB&oycbRKJN zZf=PJ?qon48OYnWZ?DUpTl`X9VWnYK-eSEVsuU(qLxO&H*k!*H7`%1KGt~FRFHfC1 z)yTl+KyTTyrOIqJ|E}zj@6FNZO)3Sh835ep3V;5WqkRsC0V zvPF$i6%NY^N;4n~%fgDSIo)mV@2BBzHBZ!nuvDM9KpzZC3PLj|`pkuT!nPFAE`w3n zEJH1XLkiF{D{3LyXvi_35mZvff3+DI1v(9zg8?5xK|j|i#Z#l>s?q8dphtmD&1h!3 z(AqJrD^#t0fGUHm038E5l&%m8yk^2+woJ*p$LZi}Q~8!92?4(wK97U{76cXa1~YUS zmjAb>Kvu{8N(VFpWFjdp%)x6fZbojFk&oByZjAdCk`P)7hv0G9VA2M$qq-D}7tV&; zLs{&mhIf;BgK|x(S1Y_LnoYG@6(m(i|%%bd(74n6yJhR*>X- z{CQn=%*j@xp?*7z8CrC9-^EvE=c1}|2{x>+zz<$M4O!GfrPfkVg0x0rZ74*QhJK4Y zP_i5zv$vR?5hIn2t&Igb91ifmRVppn)MH4HXk#xb{C+=v`u)dIwsanLJb#?}WPjA3 zFlnIqZo=spElAtiy_~-jTSi@#GZ()qkL}kd&yRl)Yj70gGB|IIQa6@$j>qHdF!wXKYIN% z25tRhv*7UIJun)yaoa0L&*Iq~Ysr?y=YGC_6B>Sd5!Y_o(&9Geq!H^pM8QuzxkApH?Cg+tsyI^ZNs`!uvaPT<4&SYP2mxwi z4?edU9)Fn6Gc_6X*t6?l9D4gRbP%vi*k0HkC&DZdw>YC+4%@UCJ#^PSCUwNdiGE{w zaXhOdXQu${!*{6P)>BIHLoIuWg_#&|Ik9^AD*l=G&RpSsPJU#=(={b{uwp*VMcU2F z9k*c}uwtNpfJSSe*NX6ZJxOgDIu*~cjL8GU)cw245P4H9qw0Z$ShaE)^0STj^SSHj zx^FEfkF8?Ga)=s~wXO<9MJYd3we0$-T$pOimmp`W0~R`txnQ*j-bO zhbjy4<~z+0L^Wh8LYvkt!;kmY;Q0HOX-*YAFnM|I6vSx2C~yL$4(?wH6LZ46fW`M4 zz20~m4|sIlm48`r_CiYktLBl zO+kw7iGezPkEv|zXZ!Vj?!SC#KHA#aap}@OQL}y#RxHVm+ctf@7$%hy7M&k&{$v-P z`sP}wwFbnB&4XpLp@EkI8JaY1>d{{L{@T0LJvglulCOW`*m-=b#*HU8lwkduVm`-i zl+E`KMi|ui$BU?Y>Z@q^;Be$gpx~T3b1k85Bi75*x`~?D3}Tt?9-AE5&x>!I!K(*0 zqUqQRe43?^KQwiYvAy?pecbl$>8sp!_8&K~WPTQYLEX|1>2vMZ2h!p;=FG=h#oF51 z9=mzV+;lm5a9}X)$uO2W65Bg=GR&Kumo!Hwiis-x;suf7$XJ!iJ}~6sH$GERv20Gt zYo@bJMP@la>N|1b#DaJqosP8kLFh@Xb-Dv+>+GMleY%p)=L}y@PAG;_TE-2<-d&`S zRa;+6UUg}$%M(!EOve~4rO7qygjBX-F-#d#`;T!KwL~srqa-PB@6=T2#GN~LrY(4O zrsPO~A01Gy(}tl_zSl7WqJlp>E7WdVUS7_+1dTxXgEfr0`uh53y83+2xrG9Q zPsq{J0aM8%(-08>Nhgo^jq+_z(Omtnj~qGj4o&-oXtFM1U^g~4u4!#;{f@`uDW*BK z0^8I@qtV!nM&lQim6d<0tE;<6Q$9fux`c$v$iTKli=!s0s;G)erA%A#B#eH0lxZNU g4hAy&(0>FN0K8&LR2ps7(*OVf07*qoM6N<$f~YXATM literal 0 HcmV?d00001 diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/login2.png new file mode 100644 index 0000000000000000000000000000000000000000..03e8eba939acaebddd108b1efb168708b9fcdeb9 GIT binary patch literal 3843 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 Hu0mjfJI@|W literal 0 HcmV?d00001 diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.bundle/images/logout_down.png new file mode 100644 index 0000000000000000000000000000000000000000..1ab14b9dc931eeb1b624cca1bbf422a2445f1754 GIT binary patch literal 1551 zcmV+q2JrcbP)4o$iGOaKRRrBWWrYV<@q2Zm^>vh`gb`7bL0j?*j)uxX` z!aYYvM{kYt{Yt0PNvTvyL#TvSUhc%Dn&b=v8ewD$pe7e3Hef0+7C>uke&WnM`uecVU1VjYbXVT!04KfB)mApl=xIvul!+E6~DBW=me9C*rZ3Qbhz3`6p%! zbgitcjL(D*4QR@y(YXY{RqdcpKI$Te&CJVReLt`C&9?agz-UujTT8K6j80EaiS1DT zHB|6CH#avt_z1YwYURN%#*Ddunae_{2Kiy%TmogY*{Hp}o!D-Q&d$#M(MODfD_D=f z$g6tBI`M8|JlqF(5BtEyJ$QL}ISmaB(bm=$9UL4e;}!$7R0^OUGFknS>X%M8zK{y> z((32IVho0XX%2^je?~o+hL=Yf{mo`GU0hu7_NX(NOuRqp1uIdH*@6Wceen6}>PlI> zF-9a3;XuQ%i9;KVfx0J^j$%^3T>7Gox}CZVKp`iMjg8dZ-L13<27|P`yv&1AS64^< z{r$>W1N{2>nidxqIXELDBUDjQq0}!eEz#xWCAGD+aYs2E4wKvM=H;E89cpQ5;qB|| z>v?cjS67R|p=gc%VsiM=ay}ZJ323kryH>C&upm;paS=-y&%RxpR+MsT5aFAwaXO&qb*e%jffF1}0$nW>l?(Qz_?d=t<`wGyZ zP$-*c&X-zmz`XjFMF1SdN-c>rCgz5Q|N9+O46U@?=W zLd+uQtNhFB`JR&Q~w$?l;(4{sk zKAoMN%1eW-$H&L~p4aQ;%G|94tl<&>s#qi#A9bAt_*OQ&STM9V|zt1B3np zMAWIyD7Zm(&<-pwCdGR;Knr#OBmtzbnVA``&Cuz|$w>u3ELyOIg#}($U0uxqgbPDI z05vf&ac?mcW1uax9(@rAaa4@pp$@WzAmKZTm5yhzKgLS|&~ye+k=BExohHK;TVp#IZLg`R`6e8?WRj}=I9swa zZH6TCua%XR3oK!m#D4$(Ev$vRluGe46JQBU$HvBf1I9X8tZ`7` zn4h2jm?iz6vaPH$l}c&<6IOt+boSP4HlMrQ?w^K-hkwSo+SJt4ypjXSV7ugFI{c0V z!7h_iKqS%{@M%&vD240^*>TW +#import + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef DEBUG +#define FBLOG +#define FBLOG2 +#else +#define FBLOG +#define FBLOG2 +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef unsigned long long FBUID; +typedef unsigned long long FBID; + +#define FBAPI_ERROR_DOMAIN @"api.facebook.com" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Error codes + +#define FBAPI_EC_SUCCESS 0 +#define FBAPI_EC_UNKNOWN 1 +#define FBAPI_EC_SERVICE 2 +#define FBAPI_EC_METHOD 3 +#define FBAPI_EC_TOO_MANY_CALLS 4 +#define FBAPI_EC_BAD_IP 5 +#define FBAPI_EC_HOST_API 6 +#define FBAPI_EC_HOST_UP 7 +#define FBAPI_EC_SECURE 8 +#define FBAPI_EC_RATE 9 +#define FBAPI_EC_PERMISSION_DENIED 10 +#define FBAPI_EC_DEPRECATED 11 +#define FBAPI_EC_VERSION 12 + +#define FBAPI_EC_PARAM 100 +#define FBAPI_EC_PARAM_FBAPI_KEY 101 +#define FBAPI_EC_PARAM_SESSION_KEY 102 +#define FBAPI_EC_PARAM_CALL_ID 103 +#define FBAPI_EC_PARAM_SIGNATURE 104 +#define FBAPI_EC_PARAM_TOO_MANY 105 +#define FBAPI_EC_PARAM_USER_ID 110 +#define FBAPI_EC_PARAM_USER_FIELD 111 +#define FBAPI_EC_PARAM_SOCIAL_FIELD 112 +#define FBAPI_EC_PARAM_EMAIL 113 +#define FBAPI_EC_PARAM_ALBUM_ID 120 +#define FBAPI_EC_PARAM_PHOTO_ID 121 +#define FBAPI_EC_PARAM_FEED_PRIORITY 130 +#define FBAPI_EC_PARAM_CATEGORY 140 +#define FBAPI_EC_PARAM_SUBCATEGORY 141 +#define FBAPI_EC_PARAM_TITLE 142 +#define FBAPI_EC_PARAM_DESCRIPTION 143 +#define FBAPI_EC_PARAM_BAD_JSON 144 +#define FBAPI_EC_PARAM_BAD_EID 150 +#define FBAPI_EC_PARAM_UNKNOWN_CITY 151 +#define FBAPI_EC_PARAM_BAD_PAGE_TYPE 152 + +#define FBAPI_EC_PERMISSION 200 +#define FBAPI_EC_PERMISSION_USER 210 +#define FBAPI_EC_PERMISSION_ALBUM 220 +#define FBAPI_EC_PERMISSION_PHOTO 221 +#define FBAPI_EC_PERMISSION_MESSAGE 230 +#define FBAPI_EC_PERMISSION_MARKUP_OTHER_USER 240 +#define FBAPI_EC_PERMISSION_STATUS_UPDATE 250 +#define FBAPI_EC_PERMISSION_PHOTO_UPLOAD 260 +#define FBAPI_EC_PERMISSION_SMS 270 +#define FBAPI_EC_PERMISSION_CREATE_LISTING 280 +#define FBAPI_EC_PERMISSION_EVENT 290 +#define FBAPI_EC_PERMISSION_LARGE_FBML_TEMPLATE 291 +#define FBAPI_EC_PERMISSION_LIVEMESSAGE 292 +#define FBAPI_EC_PERMISSION_RSVP_EVENT 299 + +#define FBAPI_EC_EDIT 300 +#define FBAPI_EC_EDIT_USER_DATA 310 +#define FBAPI_EC_EDIT_PHOTO 320 +#define FBAPI_EC_EDIT_ALBUM_SIZE 321 +#define FBAPI_EC_EDIT_PHOTO_TAG_SUBJECT 322 +#define FBAPI_EC_EDIT_PHOTO_TAG_PHOTO 323 +#define FBAPI_EC_EDIT_PHOTO_FILE 324 +#define FBAPI_EC_EDIT_PHOTO_PENDING_LIMIT 325 +#define FBAPI_EC_EDIT_PHOTO_TAG_LIMIT 326 +#define FBAPI_EC_EDIT_ALBUM_REORDER_PHOTO_NOT_IN_ALBUM 327 +#define FBAPI_EC_EDIT_ALBUM_REORDER_TOO_FEW_PHOTOS 328 +#define FBAPI_EC_MALFORMED_MARKUP 329 +#define FBAPI_EC_EDIT_MARKUP 330 +#define FBAPI_EC_EDIT_FEED_TOO_MANY_USER_CALLS 340 +#define FBAPI_EC_EDIT_FEED_TOO_MANY_USER_ACTION_CALLS 341 +#define FBAPI_EC_EDIT_FEED_TITLE_LINK 342 +#define FBAPI_EC_EDIT_FEED_TITLE_LENGTH 343 +#define FBAPI_EC_EDIT_FEED_TITLE_NAME 344 +#define FBAPI_EC_EDIT_FEED_TITLE_BLANK 345 +#define FBAPI_EC_EDIT_FEED_BODY_LENGTH 346 +#define FBAPI_EC_EDIT_FEED_PHOTO_SRC 347 +#define FBAPI_EC_EDIT_FEED_PHOTO_LINK 348 +#define FBAPI_EC_EDIT_VIDEO_SIZE 350 +#define FBAPI_EC_EDIT_VIDEO_INVALID_FILE 351 +#define FBAPI_EC_EDIT_VIDEO_INVALID_TYPE 352 +#define FBAPI_EC_EDIT_FEED_TITLE_ARRAY 360 +#define FBAPI_EC_EDIT_FEED_TITLE_PARAMS 361 +#define FBAPI_EC_EDIT_FEED_BODY_ARRAY 362 +#define FBAPI_EC_EDIT_FEED_BODY_PARAMS 363 +#define FBAPI_EC_EDIT_FEED_PHOTO 364 +#define FBAPI_EC_EDIT_FEED_TEMPLATE 365 +#define FBAPI_EC_EDIT_FEED_TARGET 366 +#define FBAPI_EC_USERS_CREATE_INVALID_EMAIL 370 +#define FBAPI_EC_USERS_CREATE_EXISTING_EMAIL 371 +#define FBAPI_EC_USERS_CREATE_BIRTHDAY 372 +#define FBAPI_EC_USERS_CREATE_PASSWORD 373 +#define FBAPI_EC_USERS_REGISTER_INVALID_CREDENTIAL 374 +#define FBAPI_EC_USERS_REGISTER_CONF_FAILURE 375 +#define FBAPI_EC_USERS_REGISTER_EXISTING 376 +#define FBAPI_EC_USERS_REGISTER_DEFAULT_ERROR 377 +#define FBAPI_EC_USERS_REGISTER_PASSWORD_BLANK 378 +#define FBAPI_EC_USERS_REGISTER_PASSWORD_INVALID_CHARS 379 +#define FBAPI_EC_USERS_REGISTER_PASSWORD_SHORT 380 +#define FBAPI_EC_USERS_REGISTER_PASSWORD_WEAK 381 +#define FBAPI_EC_USERS_REGISTER_USERNAME_ERROR 382 +#define FBAPI_EC_USERS_REGISTER_MISSING_INPUT 383 +#define FBAPI_EC_USERS_REGISTER_INCOMPLETE_BDAY 384 +#define FBAPI_EC_USERS_REGISTER_INVALID_EMAIL 385 +#define FBAPI_EC_USERS_REGISTER_EMAIL_DISABLED 386 +#define FBAPI_EC_USERS_REGISTER_ADD_USER_FAILED 387 +#define FBAPI_EC_USERS_REGISTER_NO_GENDER 388 + +#define FBAPI_EC_AUTH_EMAIL 400 +#define FBAPI_EC_AUTH_LOGIN 401 +#define FBAPI_EC_AUTH_SIG 402 +#define FBAPI_EC_AUTH_TIME 403 + +#define FBAPI_EC_SESSION_METHOD 451 +#define FBAPI_EC_SESSION_REQUIRED 453 +#define FBAPI_EC_SESSION_REQUIRED_FOR_SECRET 454 +#define FBAPI_EC_SESSION_CANNOT_USE_SESSION_SECRET 455 + +#define FBAPI_EC_MESG_BANNED 500 +#define FBAPI_EC_MESG_NO_BODY 501 +#define FBAPI_EC_MESG_TOO_LONG 502 +#define FBAPI_EC_MESG_RATE 503 +#define FBAPI_EC_MESG_INVALID_THREAD 504 +#define FBAPI_EC_MESG_INVALID_RECIP 505 +#define FBAPI_EC_POKE_INVALID_RECIP 510 +#define FBAPI_EC_POKE_OUTSTANDING 511 +#define FBAPI_EC_POKE_RATE 512 + +#define FQL_EC_UNKNOWN_ERROR 600 +#define FQL_EC_PARSER_ERROR 601 +#define FQL_EC_UNKNOWN_FIELD 602 +#define FQL_EC_UNKNOWN_TABLE 603 +#define FQL_EC_NO_INDEX 604 +#define FQL_EC_UNKNOWN_FUNCTION 605 +#define FQL_EC_INVALID_PARAM 606 +#define FQL_EC_INVALID_FIELD 607 +#define FQL_EC_INVALID_SESSION 608 + +#define FBAPI_EC_REF_SET_FAILED 700 +#define FBAPI_EC_FB_APP_UNKNOWN_ERROR 750 +#define FBAPI_EC_FB_APP_FETCH_FAILED 751 +#define FBAPI_EC_FB_APP_NO_DATA 752 +#define FBAPI_EC_FB_APP_NO_PERMISSIONS 753 +#define FBAPI_EC_FB_APP_TAG_MISSING 754 + +#define FBAPI_EC_DATA_UNKNOWN_ERROR 800 +#define FBAPI_EC_DATA_INVALID_OPERATION 801 +#define FBAPI_EC_DATA_QUOTA_EXCEEDED 802 +#define FBAPI_EC_DATA_OBJECT_NOT_FOUND 803 +#define FBAPI_EC_DATA_OBJECT_ALREADY_EXISTS 804 +#define FBAPI_EC_DATA_DATABASE_ERROR 805 +#define FBAPI_EC_DATA_CREATE_TEMPLATE_ERROR 806 +#define FBAPI_EC_DATA_TEMPLATE_EXISTS_ERROR 807 +#define FBAPI_EC_DATA_TEMPLATE_HANDLE_TOO_LONG 808 +#define FBAPI_EC_DATA_TEMPLATE_HANDLE_ALREADY_IN_USE 809 +#define FBAPI_EC_DATA_TOO_MANY_TEMPLATE_BUNDLES 810 +#define FBAPI_EC_DATA_MALFORMED_ACTION_LINK 811 +#define FBAPI_EC_DATA_TEMPLATE_USES_RESERVED_TOKEN 812 + +#define FBAPI_EC_NO_SUCH_APP 900 +#define FBAPI_BATCH_TOO_MANY_ITEMS 950 +#define FBAPI_EC_BATCH_ALREADY_STARTED 951 +#define FBAPI_EC_BATCH_NOT_STARTED 952 +#define FBAPI_EC_BATCH_METHOD_NOT_ALLOWED_IN_BATCH_MODE 953 + +#define FBAPI_EC_EVENT_INVALID_TIME 1000 +#define FBAPI_EC_INFO_NO_INFORMATION 1050 +#define FBAPI_EC_INFO_SET_FAILED 1051 + +#define FBAPI_EC_LIVEMESSAGE_SEND_FAILED 1100 +#define FBAPI_EC_LIVEMESSAGE_EVENT_NAME_TOO_LONG 1101 +#define FBAPI_EC_LIVEMESSAGE_MESSAGE_TOO_LONG 1102 + +#define FBAPI_EC_PAGES_CREATE 1201 + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +NSMutableArray* FBCreateNonRetainingArray(); + diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m new file mode 100644 index 00000000..ff85788d --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m @@ -0,0 +1,33 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBConnectGlobal.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +const void* RetainNoOp(CFAllocatorRef allocator, const void *value) { return value; } +void ReleaseNoOp(CFAllocatorRef allocator, const void *value) { } + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// public + +NSMutableArray* FBCreateNonRetainingArray() { + CFArrayCallBacks callbacks = kCFTypeArrayCallBacks; + callbacks.retain = RetainNoOp; + callbacks.release = ReleaseNoOp; + return (NSMutableArray*)CFArrayCreateMutable(nil, 0, &callbacks); +} diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h new file mode 100644 index 00000000..98205489 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.h @@ -0,0 +1,137 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBConnectGlobal.h" + +@protocol FBDialogDelegate; +@class FBSession; + +@interface FBDialog : UIView { + id _delegate; + FBSession* _session; + NSURL* _loadingURL; + UIWebView* _webView; + UIActivityIndicatorView* _spinner; + UIImageView* _iconView; + UILabel* _titleLabel; + UIButton* _closeButton; + UIDeviceOrientation _orientation; + BOOL _showingKeyboard; +} + +/** + * The delegate. + */ +@property(nonatomic,assign) id delegate; + +/** + * The session for which the login is taking place. + */ +@property(nonatomic,assign) FBSession* session; + +/** + * The title that is shown in the header atop the view; + */ +@property(nonatomic,copy) NSString* title; + +/** + * Creates the view but does not display it. + */ +- (id)initWithSession:(FBSession*)session; + +/** + * Displays the view with an animation. + * + * The view will be added to the top of the current key window. + */ +- (void)show; + +/** + * Displays the first page of the dialog. + * + * Do not ever call this directly. It is intended to be overriden by subclasses. + */ +- (void)load; + +/** + * Displays a URL in the dialog. + */ +- (void)loadURL:(NSString*)url method:(NSString*)method get:(NSDictionary*)getParams + post:(NSDictionary*)postParams; + +/** + * Hides the view and notifies delegates of success or cancellation. + */ +- (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated; + +/** + * Hides the view and notifies delegates of an error. + */ +- (void)dismissWithError:(NSError*)error animated:(BOOL)animated; + +/** + * Subclasses may override to perform actions just prior to showing the dialog. + */ +- (void)dialogWillAppear; + +/** + * Subclasses may override to perform actions just after the dialog is hidden. + */ +- (void)dialogWillDisappear; + +/** + * Subclasses should override to process data returned from the server in a 'fbconnect' url. + * + * Implementations must call dismissWithSuccess:YES at some point to hide the dialog. + */ +- (void)dialogDidSucceed:(NSURL*)url; + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol FBDialogDelegate + +@optional + +/** + * Called when the dialog succeeds and is about to be dismissed. + */ +- (void)dialogDidSucceed:(FBDialog*)dialog; + +/** + * Called when the dialog is cancelled and is about to be dismissed. + */ +- (void)dialogDidCancel:(FBDialog*)dialog; + +/** + * Called when dialog failed to load due to an error. + */ +- (void)dialog:(FBDialog*)dialog didFailWithError:(NSError*)error; + +/** + * Asks if a link touched by a user should be opened in an external browser. + * + * If a user touches a link, the default behavior is to open the link in the Safari browser, + * which will cause your app to quit. You may want to prevent this from happening, open the link + * in your own internal browser, or perhaps warn the user that they are about to leave your app. + * If so, implement this method on your delegate and return NO. If you warn the user, you + * should hold onto the URL and once you have received their acknowledgement open the URL yourself + * using [[UIApplication sharedApplication] openURL:]. + */ +- (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m new file mode 100644 index 00000000..4d10bbf5 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m @@ -0,0 +1,606 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBDialog.h" +#import "FBSession.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// global + +static NSString* kDefaultTitle = @"Connect to Facebook"; +static NSString* kStringBoundary = @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f"; + +static CGFloat kFacebookBlue[4] = {0.42578125, 0.515625, 0.703125, 1.0}; +static CGFloat kBorderGray[4] = {0.3, 0.3, 0.3, 0.8}; +static CGFloat kBorderBlack[4] = {0.3, 0.3, 0.3, 1}; +static CGFloat kBorderBlue[4] = {0.23, 0.35, 0.6, 1.0}; + +static CGFloat kTransitionDuration = 0.3; + +static CGFloat kTitleMarginX = 8; +static CGFloat kTitleMarginY = 4; +static CGFloat kPadding = 10; +static CGFloat kBorderWidth = 10; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBDialog + +@synthesize session = _session, delegate = _delegate; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (void)addRoundedRectToPath:(CGContextRef)context rect:(CGRect)rect radius:(float)radius { + CGContextBeginPath(context); + CGContextSaveGState(context); + + if (radius == 0) { + CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect)); + CGContextAddRect(context, rect); + } else { + rect = CGRectOffset(CGRectInset(rect, 0.5, 0.5), 0.5, 0.5); + CGContextTranslateCTM(context, CGRectGetMinX(rect)-0.5, CGRectGetMinY(rect)-0.5); + CGContextScaleCTM(context, radius, radius); + float fw = CGRectGetWidth(rect) / radius; + float fh = CGRectGetHeight(rect) / radius; + + CGContextMoveToPoint(context, fw, fh/2); + CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); + CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); + CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); + CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1); + } + + CGContextClosePath(context); + CGContextRestoreGState(context); +} + +- (void)drawRect:(CGRect)rect fill:(const CGFloat*)fillColors radius:(CGFloat)radius { + CGContextRef context = UIGraphicsGetCurrentContext(); + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + + if (fillColors) { + CGContextSaveGState(context); + CGContextSetFillColor(context, fillColors); + if (radius) { + [self addRoundedRectToPath:context rect:rect radius:radius]; + CGContextFillPath(context); + } else { + CGContextFillRect(context, rect); + } + CGContextRestoreGState(context); + } + + CGColorSpaceRelease(space); +} + +- (void)strokeLines:(CGRect)rect stroke:(const CGFloat*)strokeColor { + CGContextRef context = UIGraphicsGetCurrentContext(); + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + + CGContextSaveGState(context); + CGContextSetStrokeColorSpace(context, space); + CGContextSetStrokeColor(context, strokeColor); + CGContextSetLineWidth(context, 1.0); + + { + CGPoint points[] = {rect.origin.x+0.5, rect.origin.y-0.5, + rect.origin.x+rect.size.width, rect.origin.y-0.5}; + CGContextStrokeLineSegments(context, points, 2); + } + { + CGPoint points[] = {rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5, + rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}; + CGContextStrokeLineSegments(context, points, 2); + } + { + CGPoint points[] = {rect.origin.x+rect.size.width-0.5, rect.origin.y, + rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}; + CGContextStrokeLineSegments(context, points, 2); + } + { + CGPoint points[] = {rect.origin.x+0.5, rect.origin.y, + rect.origin.x+0.5, rect.origin.y+rect.size.height}; + CGContextStrokeLineSegments(context, points, 2); + } + + CGContextRestoreGState(context); + + CGColorSpaceRelease(space); +} + +- (BOOL)shouldRotateToOrientation:(UIDeviceOrientation)orientation { + if (orientation == _orientation) { + return NO; + } else { + return orientation == UIDeviceOrientationLandscapeLeft + || orientation == UIDeviceOrientationLandscapeRight + || orientation == UIDeviceOrientationPortrait + || orientation == UIDeviceOrientationPortraitUpsideDown; + } +} + +- (CGAffineTransform)transformForOrientation { + UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + if (orientation == UIInterfaceOrientationLandscapeLeft) { + return CGAffineTransformMakeRotation(M_PI*1.5); + } else if (orientation == UIInterfaceOrientationLandscapeRight) { + return CGAffineTransformMakeRotation(M_PI/2); + } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { + return CGAffineTransformMakeRotation(-M_PI); + } else { + return CGAffineTransformIdentity; + } +} + +- (void)sizeToFitOrientation:(BOOL)transform { + if (transform) { + self.transform = CGAffineTransformIdentity; + } + + CGRect frame = [UIScreen mainScreen].applicationFrame; + CGPoint center = CGPointMake( + frame.origin.x + ceil(frame.size.width/2), + frame.origin.y + ceil(frame.size.height/2)); + + CGFloat width = frame.size.width - kPadding * 2; + CGFloat height = frame.size.height - kPadding * 2; + + _orientation = [UIApplication sharedApplication].statusBarOrientation; + if (UIInterfaceOrientationIsLandscape(_orientation)) { + self.frame = CGRectMake(kPadding, kPadding, height, width); + } else { + self.frame = CGRectMake(kPadding, kPadding, width, height); + } + self.center = center; + + if (transform) { + self.transform = [self transformForOrientation]; + } +} + +- (void)updateWebOrientation { + UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + if (UIInterfaceOrientationIsLandscape(orientation)) { + [_webView stringByEvaluatingJavaScriptFromString: + @"document.body.setAttribute('orientation', 90);"]; + } else { + [_webView stringByEvaluatingJavaScriptFromString: + @"document.body.removeAttribute('orientation');"]; + } +} + +- (void)bounce1AnimationStopped { + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:kTransitionDuration/2]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(bounce2AnimationStopped)]; + self.transform = CGAffineTransformScale([self transformForOrientation], 0.9, 0.9); + [UIView commitAnimations]; +} + +- (void)bounce2AnimationStopped { + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:kTransitionDuration/2]; + self.transform = [self transformForOrientation]; + [UIView commitAnimations]; +} + +- (NSURL*)generateURL:(NSString*)baseURL params:(NSDictionary*)params { + if (params) { + NSMutableArray* pairs = [NSMutableArray array]; + for (NSString* key in params.keyEnumerator) { + NSString* value = [params objectForKey:key]; + NSString* val = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + NSString* pair = [NSString stringWithFormat:@"%@=%@", key, val]; + [pairs addObject:pair]; + } + + NSString* query = [pairs componentsJoinedByString:@"&"]; + NSString* url = [NSString stringWithFormat:@"%@?%@", baseURL, query]; + return [NSURL URLWithString:url]; + } else { + return [NSURL URLWithString:baseURL]; + } +} + +- (NSMutableData*)generatePostBody:(NSDictionary*)params { + if (!params) { + return nil; + } + + NSMutableData* body = [NSMutableData data]; + NSString* endLine = [NSString stringWithFormat:@"\r\n--%@\r\n", kStringBoundary]; + + [body appendData:[[NSString stringWithFormat:@"--%@\r\n", kStringBoundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + + for (id key in [params keyEnumerator]) { + [body appendData:[[NSString + stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] + dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[[params valueForKey:key] dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[endLine dataUsingEncoding:NSUTF8StringEncoding]]; + } + + return body; +} + +- (void)addObservers { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deviceOrientationDidChange:) + name:@"UIDeviceOrientationDidChangeNotification" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWillShow:) name:@"UIKeyboardWillShowNotification" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWillHide:) name:@"UIKeyboardWillHideNotification" object:nil]; +} + +- (void)removeObservers { + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"UIDeviceOrientationDidChangeNotification" object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"UIKeyboardWillShowNotification" object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"UIKeyboardWillHideNotification" object:nil]; +} + +- (void)postDismissCleanup { + [self removeObservers]; + [self removeFromSuperview]; +} + +- (void)dismiss:(BOOL)animated { + [self dialogWillDisappear]; + + [_loadingURL release]; + _loadingURL = nil; + + if (animated) { + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:kTransitionDuration]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(postDismissCleanup)]; + self.alpha = 0; + [UIView commitAnimations]; + } else { + [self postDismissCleanup]; + } +} + +- (void)cancel { + [self dismissWithSuccess:NO animated:YES]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSObject + +- (id)init { + return [self initWithSession:[FBSession session]]; +} + +- (id)initWithSession:(FBSession*)session { + if (self = [super initWithFrame:CGRectZero]) { + _delegate = nil; + _session = [session retain]; + _loadingURL = nil; + _orientation = UIDeviceOrientationUnknown; + _showingKeyboard = NO; + + self.backgroundColor = [UIColor clearColor]; + self.autoresizesSubviews = YES; + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.contentMode = UIViewContentModeRedraw; + + UIImage* iconImage = [UIImage imageNamed:@"FBConnect.bundle/images/fbicon.png"]; + UIImage* closeImage = [UIImage imageNamed:@"FBConnect.bundle/images/close.png"]; + + _iconView = [[UIImageView alloc] initWithImage:iconImage]; + [self addSubview:_iconView]; + + UIColor* color = [UIColor colorWithRed:167.0/255 green:184.0/255 blue:216.0/255 alpha:1]; + _closeButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; + [_closeButton setImage:closeImage forState:UIControlStateNormal]; + [_closeButton setTitleColor:color forState:UIControlStateNormal]; + [_closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; + [_closeButton addTarget:self action:@selector(cancel) + forControlEvents:UIControlEventTouchUpInside]; + _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12]; + _closeButton.showsTouchWhenHighlighted = YES; + _closeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin + | UIViewAutoresizingFlexibleBottomMargin; + [self addSubview:_closeButton]; + + _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _titleLabel.text = kDefaultTitle; + _titleLabel.backgroundColor = [UIColor clearColor]; + _titleLabel.textColor = [UIColor whiteColor]; + _titleLabel.font = [UIFont boldSystemFontOfSize:14]; + _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin + | UIViewAutoresizingFlexibleBottomMargin; + [self addSubview:_titleLabel]; + + _webView = [[UIWebView alloc] initWithFrame:CGRectZero]; + _webView.delegate = self; + _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self addSubview:_webView]; + + _spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: + UIActivityIndicatorViewStyleWhiteLarge]; + _spinner.autoresizingMask = + UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin + | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; + [self addSubview:_spinner]; + } + return self; +} + +- (void)dealloc { + _webView.delegate = nil; + [_webView release]; + [_spinner release]; + [_titleLabel release]; + [_iconView release]; + [_closeButton release]; + [_loadingURL release]; + [_session release]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// UIView + +- (void)drawRect:(CGRect)rect { + CGRect grayRect = CGRectOffset(rect, -0.5, -0.5); + [self drawRect:grayRect fill:kBorderGray radius:10]; + + CGRect headerRect = CGRectMake( + ceil(rect.origin.x + kBorderWidth), ceil(rect.origin.y + kBorderWidth), + rect.size.width - kBorderWidth*2, _titleLabel.frame.size.height); + [self drawRect:headerRect fill:kFacebookBlue radius:0]; + [self strokeLines:headerRect stroke:kBorderBlue]; + + CGRect webRect = CGRectMake( + ceil(rect.origin.x + kBorderWidth), headerRect.origin.y + headerRect.size.height, + rect.size.width - kBorderWidth*2, _webView.frame.size.height+1); + [self strokeLines:webRect stroke:kBorderBlack]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// UIWebViewDelegate + +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request + navigationType:(UIWebViewNavigationType)navigationType { + NSURL* url = request.URL; + if ([url.scheme isEqualToString:@"fbconnect"]) { + if ([url.resourceSpecifier isEqualToString:@"cancel"]) { + [self dismissWithSuccess:NO animated:YES]; + } else { + [self dialogDidSucceed:url]; + } + return NO; + } else if ([_loadingURL isEqual:url]) { + return YES; + } else if (navigationType == UIWebViewNavigationTypeLinkClicked) { + if ([_delegate respondsToSelector:@selector(dialog:shouldOpenURLInExternalBrowser:)]) { + if (![_delegate dialog:self shouldOpenURLInExternalBrowser:url]) { + return NO; + } + } + + [[UIApplication sharedApplication] openURL:request.URL]; + return NO; + } else { + return YES; + } +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView { + [_spinner stopAnimating]; + _spinner.hidden = YES; + + self.title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"]; + [self updateWebOrientation]; +} + +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { + // 102 == WebKitErrorFrameLoadInterruptedByPolicyChange + if (!([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102)) { + [self dismissWithError:error animated:YES]; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// UIDeviceOrientationDidChangeNotification + +- (void)deviceOrientationDidChange:(void*)object { + UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + if (!_showingKeyboard && [self shouldRotateToOrientation:orientation]) { + [self updateWebOrientation]; + + CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration; + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:duration]; + [self sizeToFitOrientation:YES]; + [UIView commitAnimations]; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// UIKeyboardNotifications + +- (void)keyboardWillShow:(NSNotification*)notification { + UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + if (UIInterfaceOrientationIsLandscape(orientation)) { + _webView.frame = CGRectInset(_webView.frame, + - (kPadding + kBorderWidth), + - (kPadding + kBorderWidth) - _titleLabel.frame.size.height); + } + + _showingKeyboard = YES; +} + +- (void)keyboardWillHide:(NSNotification*)notification { + UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; + if (UIInterfaceOrientationIsLandscape(orientation)) { + _webView.frame = CGRectInset(_webView.frame, + kPadding + kBorderWidth, + kPadding + kBorderWidth + _titleLabel.frame.size.height); + } + + _showingKeyboard = NO; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// public + +- (NSString*)title { + return _titleLabel.text; +} + +- (void)setTitle:(NSString*)title { + _titleLabel.text = title; +} + +- (void)show { + [self load]; + [self sizeToFitOrientation:NO]; + + CGFloat innerWidth = self.frame.size.width - (kBorderWidth+1)*2; + [_iconView sizeToFit]; + [_titleLabel sizeToFit]; + [_closeButton sizeToFit]; + + _titleLabel.frame = CGRectMake( + kBorderWidth + kTitleMarginX + _iconView.frame.size.width + kTitleMarginX, + kBorderWidth, + innerWidth - (_titleLabel.frame.size.height + _iconView.frame.size.width + kTitleMarginX*2), + _titleLabel.frame.size.height + kTitleMarginY*2); + + _iconView.frame = CGRectMake( + kBorderWidth + kTitleMarginX, + kBorderWidth + floor(_titleLabel.frame.size.height/2 - _iconView.frame.size.height/2), + _iconView.frame.size.width, + _iconView.frame.size.height); + + _closeButton.frame = CGRectMake( + self.frame.size.width - (_titleLabel.frame.size.height + kBorderWidth), + kBorderWidth, + _titleLabel.frame.size.height, + _titleLabel.frame.size.height); + + _webView.frame = CGRectMake( + kBorderWidth+1, + kBorderWidth + _titleLabel.frame.size.height, + innerWidth, + self.frame.size.height - (_titleLabel.frame.size.height + 1 + kBorderWidth*2)); + + [_spinner sizeToFit]; + [_spinner startAnimating]; + _spinner.center = _webView.center; + + UIWindow* window = [UIApplication sharedApplication].keyWindow; + if (!window) { + window = [[UIApplication sharedApplication].windows objectAtIndex:0]; + } + [window addSubview:self]; + + [self dialogWillAppear]; + + self.transform = CGAffineTransformScale([self transformForOrientation], 0.001, 0.001); + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:kTransitionDuration/1.5]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(bounce1AnimationStopped)]; + self.transform = CGAffineTransformScale([self transformForOrientation], 1.1, 1.1); + [UIView commitAnimations]; + + [self addObservers]; +} + +- (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated { + if (success) { + if ([_delegate respondsToSelector:@selector(dialogDidSucceed:)]) { + [_delegate dialogDidSucceed:self]; + } + } else { + if ([_delegate respondsToSelector:@selector(dialogDidCancel:)]) { + [_delegate dialogDidCancel:self]; + } + } + + [self dismiss:animated]; +} + +- (void)dismissWithError:(NSError*)error animated:(BOOL)animated { + if ([_delegate respondsToSelector:@selector(dialog:didFailWithError:)]) { + [_delegate dialog:self didFailWithError:error]; + } + + [self dismiss:animated]; +} + +- (void)load { + // Intended for subclasses to override +} + +- (void)loadURL:(NSString*)url method:(NSString*)method get:(NSDictionary*)getParams + post:(NSDictionary*)postParams { + // This "test cookie" is required by login.php, or it complains that you need to enable JavaScript + NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSHTTPCookie* testCookie = [NSHTTPCookie cookieWithProperties: + [NSDictionary dictionaryWithObjectsAndKeys: + @"1", NSHTTPCookieValue, + @"test_cookie", NSHTTPCookieName, + @".facebook.com", NSHTTPCookieDomain, + @"/", NSHTTPCookiePath, + nil]]; + [cookies setCookie:testCookie]; + + [_loadingURL release]; + _loadingURL = [[self generateURL:url params:getParams] retain]; + NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:_loadingURL]; + + if (method) { + [request setHTTPMethod:method]; + + if ([[method uppercaseString] isEqualToString:@"POST"]) { + NSString* contentType = [NSString + stringWithFormat:@"multipart/form-data; boundary=%@", kStringBoundary]; + [request setValue:contentType forHTTPHeaderField:@"Content-Type"]; + + NSData* body = [self generatePostBody:postParams]; + if (body) { + [request setHTTPBody:body]; + } + } + } + + [_webView loadRequest:request]; +} + +- (void)dialogWillAppear { +} + +- (void)dialogWillDisappear { +} + +- (void)dialogDidSucceed:(NSURL*)url { + [self dismissWithSuccess:YES animated:YES]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h new file mode 100644 index 00000000..50ba0f61 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.h @@ -0,0 +1,42 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBDialog.h" + +@interface FBFeedDialog : FBDialog { + long long _templateBundleId; + NSString* _templateData; + NSString* _bodyGeneral; +} + +/** + * The id for a previously registered template bundle. + */ +@property(nonatomic) long long templateBundleId; + +/** + * A JSON string containing template data. + * + * See http://wiki.developers.facebook.com/index.php/Template_Data + */ +@property(nonatomic,copy) NSString* templateData; + +/** + * Additional markup for a short story. + */ +@property(nonatomic,copy) NSString* bodyGeneral; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m new file mode 100644 index 00000000..cc310fef --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBFeedDialog.m @@ -0,0 +1,85 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBFeedDialog.h" +#import "FBSession.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// global + +static NSString* kFeedURL = @"http://www.facebook.com/connect/prompt_feed.php"; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBFeedDialog + +@synthesize templateBundleId = _templateBundleId, templateData = _templateData, + bodyGeneral = _bodyGeneral; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (NSString*)generateFeedInfo { + NSMutableArray* pairs = [NSMutableArray array]; + + if (_templateBundleId) { + [pairs addObject:[NSString stringWithFormat:@"\"template_id\": %lld", _templateBundleId]]; + } + if (_templateData) { + [pairs addObject:[NSString stringWithFormat:@"\"template_data\": %@", _templateData]]; + } + if (_bodyGeneral) { + [pairs addObject:[NSString stringWithFormat:@"\"body_general\": \"%@\"", _bodyGeneral]]; + } + + return [NSString stringWithFormat:@"{%@}", [pairs componentsJoinedByString:@","]]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSObject + +- (id)initWithSession:(FBSession*)session { + if (self = [super initWithSession:session]) { + _templateBundleId = 0; + _templateData = nil; + _bodyGeneral = nil; + } + return self; +} + +- (void)dealloc { + [_templateData release]; + [_bodyGeneral release]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// FBDialog + +- (void)load { + NSDictionary* getParams = [NSDictionary dictionaryWithObjectsAndKeys: + @"touch", @"display", nil]; + + NSString* feedInfo = [self generateFeedInfo]; + NSDictionary* postParams = [NSDictionary dictionaryWithObjectsAndKeys: + _session.apiKey, @"api_key", _session.sessionKey, @"session_key", + @"1", @"preview", @"fbconnect:success", @"callback", @"fbconnect:cancel", @"cancel", + feedInfo, @"feed_info", @"self_feed", @"feed_target_type", nil]; + + [self loadURL:kFeedURL method:@"POST" get:getParams post:postParams]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h new file mode 100644 index 00000000..4f98f4f5 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.h @@ -0,0 +1,49 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBSession.h" + +typedef enum { + FBLoginButtonStyleNormal, + FBLoginButtonStyleWide, +} FBLoginButtonStyle; + +/** + * Standard button which lets the user log in or out of the session. + * + * The button will automatically change to reflect the state of the session, showing + * "login" if the session is not connected, and "logout" if the session is connected. + */ +@interface FBLoginButton : UIControl { + FBLoginButtonStyle _style; + FBSession* _session; + UIImageView* _imageView; +} + +/** + * The visual style of the button. + */ +@property(nonatomic) FBLoginButtonStyle style; + +/** + * The session object that the button will log in and out of. + * + * The default value is the global session singleton, so there is usually no need to + * set this property yourself. + */ +@property(nonatomic,retain) FBSession* session; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m new file mode 100644 index 00000000..92bfb27a --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m @@ -0,0 +1,162 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBLoginButton.h" +#import "FBLoginDialog.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBLoginButton + +@synthesize session = _session, style = _style; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (UIImage*)buttonImage { + if (_session.isConnected) { + return [UIImage imageNamed:@"FBConnect.bundle/images/logout.png"]; + } else { + if (_style == FBLoginButtonStyleNormal) { + return [UIImage imageNamed:@"FBConnect.bundle/images/login.png"]; + } else if (_style == FBLoginButtonStyleWide) { + return [UIImage imageNamed:@"FBConnect.bundle/images/login2.png"]; + } else { + return nil; + } + } +} + +- (UIImage*)buttonHighlightedImage { + if (_session.isConnected) { + return [UIImage imageNamed:@"FBConnect.bundle/images/logout_down.png"]; + } else { + if (_style == FBLoginButtonStyleNormal) { + return [UIImage imageNamed:@"FBConnect.bundle/images/login_down.png"]; + } else if (_style == FBLoginButtonStyleWide) { + return [UIImage imageNamed:@"FBConnect.bundle/images/login2_down.png"]; + } else { + return nil; + } + } +} + +- (void)updateImage { + if (self.highlighted) { + _imageView.image = [self buttonHighlightedImage]; + } else { + _imageView.image = [self buttonImage]; + } +} + +- (void)touchUpInside { + if (_session.isConnected) { + [_session logout]; + } else { + FBLoginDialog* dialog = [[[FBLoginDialog alloc] initWithSession:_session] autorelease]; + [dialog show]; + } +} + +- (void)initButton { + _style = FBLoginButtonStyleNormal; + + _imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; + _imageView.contentMode = UIViewContentModeCenter; + [self addSubview:_imageView]; + + self.backgroundColor = [UIColor clearColor]; + [self addTarget:self action:@selector(touchUpInside) + forControlEvents:UIControlEventTouchUpInside]; + + self.session = [FBSession session]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSObject + +- (id)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + [self initButton]; + if (CGRectIsEmpty(frame)) { + [self sizeToFit]; + } + } + return self; +} + +- (void)awakeFromNib { + [self initButton]; +} + +- (void)dealloc { + [_session.delegates removeObject:self]; + [_session release]; + [_imageView release]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// UIView + +- (CGSize)sizeThatFits:(CGSize)size { + return _imageView.image.size; +} + +- (void)layoutSubviews { + _imageView.frame = self.bounds; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// UIControl + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + [self updateImage]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// FBSessionDelegate + +- (void)session:(FBSession*)session didLogin:(FBUID)uid { + [self updateImage]; +} + +- (void)sessionDidLogout:(FBSession*)session { + [self updateImage]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// public + +- (void)setSession:(FBSession*)session { + if (session != _session) { + [_session.delegates removeObject:self]; + [_session release]; + _session = [session retain]; + [_session.delegates addObject:self]; + + [self updateImage]; + } +} + +- (void)setStyle:(FBLoginButtonStyle)style { + _style = style; + + [self updateImage]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h new file mode 100644 index 00000000..8eb0b908 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.h @@ -0,0 +1,24 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBDialog.h" +#import "FBRequest.h" + +@interface FBLoginDialog : FBDialog { + FBRequest* _getSessionRequest; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m new file mode 100644 index 00000000..63058f3e --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m @@ -0,0 +1,129 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBLoginDialog.h" +#import "FBSession.h" +#import "FBRequest.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// global + +static NSString* kLoginURL = @"http://www.facebook.com/login.php"; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBLoginDialog + +//@synthesize session = _session; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (void)connectToGetSession:(NSString*)token { + _getSessionRequest = [[FBRequest requestWithSession:_session delegate:self] retain]; + NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObject:token forKey:@"auth_token"]; + if (!_session.apiSecret) { + [params setObject:@"1" forKey:@"generate_session_secret"]; + } + + if (_session.getSessionProxy) { + [_getSessionRequest post:_session.getSessionProxy params:params]; + } else { + [_getSessionRequest call:@"facebook.auth.getSession" params:params]; + } +} + +- (void)loadLoginPage { + NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: + @"1", @"fbconnect", @"touch", @"connect_display", _session.apiKey, @"api_key", + @"fbconnect://success", @"next", nil]; + + [self loadURL:kLoginURL method:@"GET" get:params post:nil]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSObject + +- (id)initWithSession:(FBSession*)session { + if (self = [super initWithSession:session]) { + _getSessionRequest = nil; + } + return self; +} + +- (void)dealloc { + _getSessionRequest.delegate = nil; + [_getSessionRequest release]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// FBDialog + +- (void)load { + [self loadLoginPage]; +} + +- (void)dialogWillDisappear { + [_webView stringByEvaluatingJavaScriptFromString:@"email.blur();"]; + + [_getSessionRequest cancel]; +} + +- (void)dialogDidSucceed:(NSURL*)url { + NSString* q = url.query; + NSRange start = [q rangeOfString:@"auth_token="]; + if (start.location != NSNotFound) { + NSRange end = [q rangeOfString:@"&"]; + NSUInteger offset = start.location+start.length; + NSString* token = end.location == NSNotFound + ? [q substringFromIndex:offset] + : [q substringWithRange:NSMakeRange(offset, end.location-offset)]; + + if (token) { + [self connectToGetSession:token]; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// FBRequestDelegate + +- (void)request:(FBRequest*)request didLoad:(id)result { + NSDictionary* object = result; + FBUID uid = [[object objectForKey:@"uid"] intValue]; + NSString* sessionKey = [object objectForKey:@"session_key"]; + NSString* sessionSecret = [object objectForKey:@"secret"]; + NSTimeInterval expires = [[object objectForKey:@"expires"] floatValue]; + NSDate* expiration = expires ? [NSDate dateWithTimeIntervalSince1970:expires] : nil; + + [_getSessionRequest release]; + _getSessionRequest = nil; + + [_session begin:uid sessionKey:sessionKey sessionSecret:sessionSecret expires:expiration]; + [_session resume]; + + [self dismissWithSuccess:YES animated:YES]; +} + +- (void)request:(FBRequest*)request didFailWithError:(NSError*)error { + [_getSessionRequest release]; + _getSessionRequest = nil; + + [self dismissWithError:error animated:YES]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h new file mode 100644 index 00000000..d203ddbe --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.h @@ -0,0 +1,31 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBLoginDialog.h" + +@interface FBPermissionDialog : FBLoginDialog { + NSString* _permission; + NSTimer* _redirectTimer; +} + +/** + * The extended permission to request. + * + * See http://wiki.developers.facebook.com/index.php/Extended_permissions + */ +@property(nonatomic,copy) NSString* permission; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m new file mode 100644 index 00000000..794964a2 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBPermissionDialog.m @@ -0,0 +1,100 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBPermissionDialog.h" +#import "FBSession.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// global + +static NSString* kPermissionURL = @"http://www.facebook.com/connect/prompt_permission.php"; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBPermissionDialog + +@synthesize permission = _permission; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (void)redirectToLogin { + _redirectTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self + selector:@selector(redirectToLoginDelayed) userInfo:nil repeats:NO]; +} + +- (void)redirectToLoginDelayed { + _redirectTimer = nil; + + // This loads the login page, which will just redirect back to the callback url + // since the login cookies are set + [super load]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSObject + +- (id)initWithSession:(FBSession*)session { + if (self = [super initWithSession:session]) { + _permission = nil; + _redirectTimer = nil; + } + return self; +} + +- (void)dealloc { + [_redirectTimer invalidate]; + [_permission release]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// FBDialog + +- (void)load { + NSDictionary* params = [NSDictionary dictionaryWithObjectsAndKeys: + @"touch", @"display", _session.apiKey, @"api_key", _session.sessionKey, @"session_key", + _permission, @"ext_perm", @"fbconnect:success", @"next", @"fbconnect:cancel", @"cancel", nil]; + + [self loadURL:kPermissionURL method:@"GET" get:params post:nil]; +} + +- (void)dialogDidSucceed:(NSURL*)url { + if ([_permission isEqualToString:@"offline_access"]) { + [super dialogDidSucceed:url]; + } else { + [self dismissWithSuccess:YES animated:YES]; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// UIWebViewDelegate + +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request + navigationType:(UIWebViewNavigationType)navigationType { + if ([_permission isEqualToString:@"offline_access"]) { + NSURL* url = request.URL; + if ([url.scheme isEqualToString:@"fbconnect"]) { + if ([url.resourceSpecifier isEqualToString:@"success"]) { + [self redirectToLogin]; + return NO; + } + } + } + return [super webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h new file mode 100644 index 00000000..66950b61 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h @@ -0,0 +1,165 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FBConnectGlobal.h" + +@protocol FBRequestDelegate; +@class FBSession; + +@interface FBRequest : NSObject { + FBSession* _session; + id _delegate; + NSString* _url; + NSString* _method; + id _userInfo; + NSMutableDictionary* _params; + NSObject* _dataParam; + NSDate* _timestamp; + NSURLConnection* _connection; + NSMutableData* _responseText; +} + +/** + * Creates a new API request for the global session. + */ ++ (FBRequest*)request; + +/** + * Creates a new API request for the global session with a delegate. + */ ++ (FBRequest*)requestWithDelegate:(id)delegate; + +/** + * Creates a new API request for a particular session. + */ ++ (FBRequest*)requestWithSession:(FBSession*)session; + +/** + * Creates a new API request for the global session with a delegate. + */ ++ (FBRequest*)requestWithSession:(FBSession*)session delegate:(id)delegate; + +@property(nonatomic,assign) id delegate; + +/** + * The URL which will be contacted to execute the request. + */ +@property(nonatomic,readonly) NSString* url; + +/** + * The API method which will be called. + */ +@property(nonatomic,readonly) NSString* method; + +/** + * An object used by the user of the request to help identify the meaning of the request. + */ +@property(nonatomic,retain) id userInfo; + +/** + * The dictionary of parameters to pass to the method. + * + * These values in the dictionary will be converted to strings using the + * standard Objective-C object-to-string conversion facilities. + */ +@property(nonatomic,readonly) NSDictionary* params; + +/** + * A data parameter. + * + * Used for methods such as photos.upload, video.upload, events.create, and + * events.edit. + */ +@property(nonatomic,readonly) NSObject* dataParam; + +/** + * The timestamp of when the request was sent to the server. + */ +@property(nonatomic,readonly) NSDate* timestamp; + +/** + * Indicates if the request has been sent and is awaiting a response. + */ +@property(nonatomic,readonly) BOOL loading; + +/** + * Creates a new request paired to a session. + */ +- (id)initWithSession:(FBSession*)session; + +/** + * Calls a method on the server asynchronously. + * + * The delegate will be called for each stage of the loading process. + */ +- (void)call:(NSString*)method params:(NSDictionary*)params; + +/** + * Calls a method on the server asynchronously, with a file upload component. + * + * The delegate will be called for each stage of the loading process. + */ +- (void)call:(NSString*)method params:(NSDictionary*)params dataParam:(NSData*)dataParam; + +/** + * Calls a URL on the server asynchronously. + * + * The delegate will be called for each stage of the loading process. + */ +- (void)post:(NSString*)url params:(NSDictionary*)params; + +/** + * Stops an active request before the response has returned. + */ +- (void)cancel; + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol FBRequestDelegate + +@optional + +/** + * Called just before the request is sent to the server. + */ +- (void)requestLoading:(FBRequest*)request; + +/** + * Called when the server responds and begins to send back data. + */ +- (void)request:(FBRequest*)request didReceiveResponse:(NSURLResponse*)response; + +/** + * Called when an error prevents the request from completing successfully. + */ +- (void)request:(FBRequest*)request didFailWithError:(NSError*)error; + +/** + * Called when a request returns and its response has been parsed into an object. + * + * The resulting object may be a dictionary, an array, a string, or a number, depending + * on thee format of the API response. + */ +- (void)request:(FBRequest*)request didLoad:(id)result; + +/** + * Called when the request was cancelled. + */ +- (void)requestWasCancelled:(FBRequest*)request; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m new file mode 100644 index 00000000..08dcfc40 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m @@ -0,0 +1,378 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FBRequest.h" +#import "FBSession.h" +#import "FBXMLHandler.h" +#import + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// global + +static NSString* kAPIVersion = @"1.0"; +static NSString* kAPIFormat = @"XML"; +static NSString* kUserAgent = @"FacebookConnect"; +static NSString* kStringBoundary = @"3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f"; + +static const NSTimeInterval kTimeoutInterval = 180.0; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBRequest + +@synthesize delegate = _delegate, +url = _url, +method = _method, +params = _params, +dataParam = _dataParam, +userInfo = _userInfo, +timestamp = _timestamp; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// class public + ++ (FBRequest*)request { + return [self requestWithSession:[FBSession session]]; +} + ++ (FBRequest*)requestWithDelegate:(id)delegate { + return [self requestWithSession:[FBSession session] delegate:delegate]; +} + ++ (FBRequest*)requestWithSession:(FBSession*)session { + return [[[FBRequest alloc] initWithSession:session] autorelease]; +} + ++ (FBRequest*)requestWithSession:(FBSession*)session delegate:(id)delegate { + FBRequest* request = [[[FBRequest alloc] initWithSession:session] autorelease]; + request.delegate = delegate; + return request; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (NSString*)md5HexDigest:(NSString*)input { + const char* str = [input UTF8String]; + unsigned char result[CC_MD5_DIGEST_LENGTH]; + CC_MD5(str, strlen(str), result); + + NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; + for(int i = 0; i", _method ? _method : _url]; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// NSURLConnectionDelegate + +- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { + _responseText = [[NSMutableData alloc] init]; + + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; + if ([_delegate respondsToSelector:@selector(request:didReceiveResponse:)]) { + [_delegate request:self didReceiveResponse:httpResponse]; + } +} + +- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { + [_responseText appendData:data]; +} + +- (NSCachedURLResponse*)connection:(NSURLConnection*)connection + willCacheResponse:(NSCachedURLResponse*)cachedResponse { + return nil; +} + +- (void)connectionDidFinishLoading:(NSURLConnection*)connection { + [self handleResponseData:_responseText]; + + [_responseText release]; + _responseText = nil; + [_connection release]; + _connection = nil; +} + +- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { + [self failWithError:error]; + + [_responseText release]; + _responseText = nil; + [_connection release]; + _connection = nil; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +// public + +- (BOOL)loading { + return !!_connection; +} + +- (void)call:(NSString*)method params:(NSDictionary*)params { + [self call:method params:params dataParam:nil]; +} + +- (void)call:(NSString*)method params:(NSDictionary*)params dataParam:(NSData*)dataParam { + _url = [[self urlForMethod:method] retain]; + _method = [method copy]; + _params = params + ? [[NSMutableDictionary alloc] initWithDictionary:params] + : [[NSMutableDictionary alloc] init]; + _dataParam = dataParam; + + [_params setObject:_method forKey:@"method"]; + [_params setObject:_session.apiKey forKey:@"api_key"]; + [_params setObject:kAPIVersion forKey:@"v"]; + [_params setObject:kAPIFormat forKey:@"format"]; + + if (![self isSpecialMethod]) { + [_params setObject:_session.sessionKey forKey:@"session_key"]; + [_params setObject:[self generateCallId] forKey:@"call_id"]; + + if (_session.sessionSecret) { + [_params setObject:@"1" forKey:@"ss"]; + } + } + + [_params setObject:[self generateSig] forKey:@"sig"]; + + [_session send:self]; +} + +- (void)post:(NSString*)url params:(NSDictionary*)params { + _url = [url retain]; + _params = params + ? [[NSMutableDictionary alloc] initWithDictionary:params] + : [[NSMutableDictionary alloc] init]; + + [_session send:self]; +} + +- (void)cancel { + if (_connection) { + [_connection cancel]; + [_connection release]; + _connection = nil; + + if ([_delegate respondsToSelector:@selector(requestWasCancelled:)]) { + [_delegate requestWasCancelled:self]; + } + } +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h new file mode 100644 index 00000000..edbfd3d5 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h @@ -0,0 +1,188 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBConnectGlobal.h" + +@protocol FBSessionDelegate; +@class FBRequest; + +/** + * An FBSession represents a single user's authenticated session for a Facebook application. + * + * To create a session, you must use the session key of your application (which can + * be found on the Facebook developer website). You may then use the login dialog to ask + * the user to enter their email address and password. If successful, you will get back a + * session key which can be used to make requests to the Facebook API. + * + * Session keys are cached and stored on the disk of the device so that you do not need to ask + * the user to login every time they launch the app. To restore the last active session, call the + * resume method after instantiating your session. + */ +@interface FBSession : NSObject { + NSMutableArray* _delegates; + NSString* _apiKey; + NSString* _apiSecret; + NSString* _getSessionProxy; + FBUID _uid; + NSString* _sessionKey; + NSString* _sessionSecret; + NSDate* _expirationDate; + NSMutableArray* _requestQueue; + NSDate* _lastRequestTime; + int _requestBurstCount; + NSTimer* _requestTimer; +} + +/** + * Delegates which implement FBSessionDelegate. + */ +@property(nonatomic,readonly) NSMutableArray* delegates; + +/** + * The URL used for API HTTP requests. + */ +@property(nonatomic,readonly) NSString* apiURL; + +/** + * The URL used for secure API HTTP requests. + */ +@property(nonatomic,readonly) NSString* apiSecureURL; + +/** + * Your application's API key, as passed to the constructor. + */ +@property(nonatomic,readonly) NSString* apiKey; + +/** + * Your application's API secret, as passed to the constructor. + */ +@property(nonatomic,readonly) NSString* apiSecret; + +/** + * The URL to call to create a session key after login. + * + * This is an alternative to calling auth.getSession directly using the secret key. + */ +@property(nonatomic,readonly) NSString* getSessionProxy; + +/** + * The current user's Facebook id. + */ +@property(nonatomic,readonly) FBUID uid; + +/** + * The current user's session key. + */ +@property(nonatomic,readonly) NSString* sessionKey; + +/** + * The current user's session secret. + */ +@property(nonatomic,readonly) NSString* sessionSecret; + +/** + * The expiration date of the session key. + */ +@property(nonatomic,readonly) NSDate* expirationDate; + +/** + * Determines if the session is active and connected to a user. + */ +@property(nonatomic,readonly) BOOL isConnected; + +/** + * The globally shared session instance. + */ ++ (FBSession*)session; + +/** + * Sets the globally shared session instance. + * + * This session is not retained, so you are still responsible for retaining it yourself. The + * first session that is created is automatically stored here. + */ ++ (void)setSession:(FBSession*)session; + +/** + * Constructs a session and stores it as the globally shared session instance. + * + * @param secret the application secret (optional) + */ ++ (FBSession*)sessionForApplication:(NSString*)key secret:(NSString*)secret + delegate:(id)delegate; + +/** + * Constructs a session and stores it as the global singleton. + * + * @param getSessionProxy a url to that proxies auth.getSession (optional) + */ ++ (FBSession*)sessionForApplication:(NSString*)key getSessionProxy:(NSString*)getSessionProxy + delegate:(id)delegate; + +/** + * Constructs a session for an application. + * + * @param secret the application secret (optional) + * @param getSessionProxy a url to that proxies auth.getSession (optional) + */ +- (FBSession*)initWithKey:(NSString*)key secret:(NSString*)secret + getSessionProxy:(NSString*)getSessionProxy; + +/** + * Begins a session for a user with a given key and secret. + */ +- (void)begin:(FBUID)uid sessionKey:(NSString*)sessionKey sessionSecret:(NSString*)sessionSecret + expires:(NSDate*)expires; + +/** + * Resumes a previous session whose uid, session key, and secret are cached on disk. + */ +- (BOOL)resume; + +/** + * Ends the current session and deletes the uid, session key, and secret from disk. + */ +- (void)logout; + +/** + * Sends a fully configured request to the server for execution. + */ +- (void)send:(FBRequest*)request; + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@protocol FBSessionDelegate + +/** + * Called when a user has successfully logged in and begun a session. + */ +- (void)session:(FBSession*)session didLogin:(FBUID)uid; + +@optional + +/** + * Called when a session is about to log out. + */ +- (void)session:(FBSession*)session willLogout:(FBUID)uid; + +/** + * Called when a session has logged out. + */ +- (void)sessionDidLogout:(FBSession*)session; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m new file mode 100644 index 00000000..2855765f --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m @@ -0,0 +1,286 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBSession.h" +#import "FBRequest.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// global + +static NSString* kAPIRestURL = @"http://api.facebook.com/restserver.php"; +static NSString* kAPIRestSecureURL = @"https://api.facebook.com/restserver.php"; + +static const int kMaxBurstRequests = 3; +static const NSTimeInterval kBurstDuration = 2; + +static FBSession* sharedSession = nil; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBSession + +@synthesize delegates = _delegates, apiKey = _apiKey, apiSecret = _apiSecret, + getSessionProxy = _getSessionProxy, uid = _uid, sessionKey = _sessionKey, + sessionSecret = _sessionSecret, expirationDate = _expirationDate; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// class public + ++ (FBSession*)session { + return sharedSession; +} + ++ (void)setSession:(FBSession*)session { + sharedSession = session; +} + ++ (FBSession*)sessionForApplication:(NSString*)key secret:(NSString*)secret + delegate:(id)delegate { + FBSession* session = [[[FBSession alloc] initWithKey:key secret:secret + getSessionProxy:nil] autorelease]; + [session.delegates addObject:delegate]; + return session; +} + ++ (FBSession*)sessionForApplication:(NSString*)key getSessionProxy:(NSString*)getSessionProxy + delegate:(id)delegate { + FBSession* session = [[[FBSession alloc] initWithKey:key secret:nil + getSessionProxy:getSessionProxy] autorelease]; + [session.delegates addObject:delegate]; + return session; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (void)save { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if (_uid) { + [defaults setInteger:_uid forKey:@"FBUserId"]; + } else { + [defaults removeObjectForKey:@"FBUserId"]; + } + + if (_sessionKey) { + [defaults setObject:_sessionKey forKey:@"FBSessionKey"]; + } else { + [defaults removeObjectForKey:@"FBSessionKey"]; + } + + if (_sessionSecret) { + [defaults setObject:_sessionSecret forKey:@"FBSessionSecret"]; + } else { + [defaults removeObjectForKey:@"FBSessionSecret"]; + } + + if (_expirationDate) { + [defaults setObject:_expirationDate forKey:@"FBSessionExpires"]; + } else { + [defaults removeObjectForKey:@"FBSessionExpires"]; + } + + [defaults synchronize]; +} + +- (void)unsave { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:@"FBUserId"]; + [defaults removeObjectForKey:@"FBSessionKey"]; + [defaults removeObjectForKey:@"FBSessionSecret"]; + [defaults removeObjectForKey:@"FBSessionExpires"]; + [defaults synchronize]; +} + +- (void)startFlushTimer { + if (!_requestTimer) { + NSTimeInterval t = kBurstDuration + [_lastRequestTime timeIntervalSinceNow]; + _requestTimer = [NSTimer scheduledTimerWithTimeInterval:t target:self + selector:@selector(requestTimerReady) userInfo:nil repeats:NO]; + } +} + +- (void)enqueueRequest:(FBRequest*)request { + [_requestQueue addObject:request]; + [self startFlushTimer]; +} + +- (BOOL)performRequest:(FBRequest*)request enqueue:(BOOL)enqueue { + // Stagger requests that happen in short bursts to prevent the server from rejecting + // them for making too many requests in a short time + NSTimeInterval t = [_lastRequestTime timeIntervalSinceNow]; + BOOL burst = t && t > -kBurstDuration; + if (burst && ++_requestBurstCount > kMaxBurstRequests) { + if (enqueue) { + [self enqueueRequest:request]; + } + return NO; + } else { + [request performSelector:@selector(connect)]; + + if (!burst) { + _requestBurstCount = 1; + [_lastRequestTime release]; + _lastRequestTime = [[request timestamp] retain]; + } + } + return YES; +} + +- (void)flushRequestQueue { + while (_requestQueue.count) { + FBRequest* request = [_requestQueue objectAtIndex:0]; + if ([self performRequest:request enqueue:NO]) { + [_requestQueue removeObjectAtIndex:0]; + } else { + [self startFlushTimer]; + break; + } + } +} + +- (void)requestTimerReady { + _requestTimer = nil; + [self flushRequestQueue]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSObject + +- (FBSession*)initWithKey:(NSString*)key secret:(NSString*)secret + getSessionProxy:(NSString*)getSessionProxy { + if (self = [super init]) { + if (!sharedSession) { + sharedSession = self; + } + + _delegates = FBCreateNonRetainingArray(); + _apiKey = [key copy]; + _apiSecret = [secret copy]; + _getSessionProxy = [getSessionProxy copy]; + _uid = 0; + _sessionKey = nil; + _sessionSecret = nil; + _expirationDate = nil; + _requestQueue = [[NSMutableArray alloc] init]; + _lastRequestTime = nil; + _requestBurstCount = 0; + _requestTimer = nil; + } + return self; +} + +- (void)dealloc { + if (sharedSession == self) { + sharedSession = nil; + } + + [_delegates release]; + [_requestQueue release]; + [_apiKey release]; + [_apiSecret release]; + [_getSessionProxy release]; + [_sessionKey release]; + [_sessionSecret release]; + [_expirationDate release]; + [_lastRequestTime release]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// public + +- (NSString*)apiURL { + return kAPIRestURL; +} + +- (NSString*)apiSecureURL { + return kAPIRestSecureURL; +} + +- (BOOL)isConnected { + return !!_sessionKey; +} + +- (void)begin:(FBUID)uid sessionKey:(NSString*)sessionKey + sessionSecret:(NSString*)sessionSecret expires:(NSDate*)expires { + _uid = uid; + _sessionKey = [sessionKey copy]; + _sessionSecret = [sessionSecret copy]; + _expirationDate = [expires retain]; + + [self save]; +} + +- (BOOL)resume { + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + FBUID uid = [defaults integerForKey:@"FBUserId"]; + if (uid) { + NSDate* expirationDate = [defaults objectForKey:@"FBSessionExpires"]; + if (!expirationDate || [expirationDate timeIntervalSinceNow] > 0) { + _uid = uid; + _sessionKey = [[defaults stringForKey:@"FBSessionKey"] copy]; + _sessionSecret = [[defaults stringForKey:@"FBSessionSecret"] copy]; + _expirationDate = [expirationDate retain]; + + for (id delegate in _delegates) { + [delegate session:self didLogin:_uid]; + } + return YES; + } + } + return NO; +} + +- (void)logout { + if (_sessionKey) { + for (id delegate in _delegates) { + if ([delegate respondsToSelector:@selector(session:willLogout:)]) { + [delegate session:self willLogout:_uid]; + } + } + + // Remove cookies that UIWebView may have stored + NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray* facebookCookies = [cookies cookiesForURL: + [NSURL URLWithString:@"http://login.facebook.com"]]; + for (NSHTTPCookie* cookie in facebookCookies) { + [cookies deleteCookie:cookie]; + } + + _uid = 0; + [_sessionKey release]; + _sessionKey = nil; + [_sessionSecret release]; + _sessionSecret = nil; + [_expirationDate release]; + _expirationDate = nil; + [self unsave]; + + for (id delegate in _delegates) { + if ([delegate respondsToSelector:@selector(sessionDidLogout:)]) { + [delegate sessionDidLogout:self]; + } + } + } else { + [self unsave]; + } +} + +- (void)send:(FBRequest*)request { + [self performRequest:request enqueue:YES]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h new file mode 100755 index 00000000..b926a01e --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.h @@ -0,0 +1,62 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FBDialog.h" + +@interface FBStreamDialog : FBDialog { + NSString* _attachment; + NSString* _actionLinks; + NSString* _targetId; + NSString* _userMessagePrompt; +} + +/** + * A JSON-encoded object containing the text of the post, relevant links, a + * media type (image, video, mp3, flash), as well as any other key/value pairs + * you may want to add. + * + * Note: If you want to use this call to update a user's status, don't pass an + * attachment; the content of the userMessage parameter will become the user's + * new status and will appear at the top of the user's profile. + * + * For more info, see http://wiki.developers.facebook.com/index.php/Attachment_(Streams) + */ +@property(nonatomic,copy) NSString* attachment; + +/** + * A JSON-encoded array of action link objects, containing the link text and a + * hyperlink. + */ +@property(nonatomic,copy) NSString* actionLinks; + +/** + * The ID of the user or the Page where you are publishing the content. If this + * is specified, the post appears on the Wall of the target user, not on the + * Wall of the user who published the post. This mimics the action of posting + * on a friend's Wall on Facebook itself. + * + * Note: To post on the user's own wall, leave this blank. + */ +@property(nonatomic,copy) NSString* targetId; + +/** + * Text you provide the user as a prompt to specify a userMessage. This appears + * above the box where the user enters a custom message. + * For example, "What's on your mind?" + */ +@property(nonatomic,copy) NSString* userMessagePrompt; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m new file mode 100755 index 00000000..99fdf142 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBStreamDialog.m @@ -0,0 +1,77 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FBStreamDialog.h" +#import "FBSession.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// global + +static NSString* kStreamURL = @"http://www.facebook.com/connect/prompt_feed.php"; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBStreamDialog + +@synthesize attachment = _attachment, + actionLinks = _actionLinks, + targetId = _targetId, + userMessagePrompt = _userMessagePrompt; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSObject + +- (id)initWithSession:(FBSession*)session { + if (self = [super initWithSession:session]) { + _attachment = @""; + _actionLinks = @""; + _targetId = @""; + _userMessagePrompt = @""; + } + return self; +} + +- (void)dealloc { + [_attachment release]; + [_actionLinks release]; + [_targetId release]; + [_userMessagePrompt release]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// FBDialog + +- (void)load { + NSDictionary* getParams = [NSDictionary dictionaryWithObjectsAndKeys: + @"touch", @"display", nil]; + + NSDictionary* postParams = [NSDictionary dictionaryWithObjectsAndKeys: + _session.apiKey, @"api_key", + _session.sessionKey, @"session_key", + @"1", @"preview", + @"fbconnect:success", @"callback", + @"fbconnect:cancel", @"cancel", + _attachment, @"attachment", + _actionLinks, @"action_links", + _targetId, @"target_id", + _userMessagePrompt, @"user_message_prompt", + nil]; + + [self loadURL:kStreamURL method:@"POST" get:getParams post:postParams]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h new file mode 100644 index 00000000..a60ef6ad --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h @@ -0,0 +1,32 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBConnectGlobal.h" + +@interface FBXMLHandler : NSObject { + NSMutableArray* _stack; + NSMutableArray* _nameStack; + id _rootObject; + NSString* _rootName; + NSMutableString* _chars; + NSError* _parseError; +} + +@property(nonatomic,readonly) id rootObject; +@property(nonatomic,readonly) NSString* rootName; +@property(nonatomic,readonly) NSError* parseError; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m new file mode 100644 index 00000000..d8b1f745 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m @@ -0,0 +1,152 @@ +/* + * Copyright 2009 Facebook + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +#import "FBXMLHandler.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation FBXMLHandler + +@synthesize rootObject = _rootObject, rootName = _rootName, parseError = _parseError; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// private + +- (NSString*)topName { + return [_nameStack lastObject]; +} + +- (id)topObject:(BOOL)create { + id object = [_stack objectAtIndex:_stack.count-1]; + if (object == [NSNull null] && create) { + object = [NSMutableDictionary dictionary]; + [_stack replaceObjectAtIndex:_stack.count-1 withObject:object]; + } + return object; +} + +- (id)topContainer { + if (_stack.count < 2) { + return nil; + } else { + id object = [_stack objectAtIndex:_stack.count-2]; + if (object == [NSNull null]) { + object = [NSMutableDictionary dictionary]; + [_stack replaceObjectAtIndex:_stack.count-2 withObject:object]; + } + return object; + } +} + +- (void)flushCharacters { + NSCharacterSet* whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + for (NSInteger i = 0; i < _chars.length; ++i) { + unichar c = [_chars characterAtIndex:i]; + if (![whitespace characterIsMember:c]) { + id topContainer = self.topContainer; + if ([topContainer isKindOfClass:[NSMutableArray class]]) { + id object = [NSDictionary dictionaryWithObject:_chars forKey:self.topName]; + [_stack replaceObjectAtIndex:_stack.count-1 withObject:object]; + } else { + [_stack replaceObjectAtIndex:_stack.count-1 withObject:_chars]; + } + break; + } + } + + [_chars release]; + _chars = nil; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSObject + +- (id)init { + if (self = [super init]) { + _stack = [[NSMutableArray alloc] init]; + _nameStack = [[NSMutableArray alloc] init]; + _rootObject = nil; + _rootName = nil; + _chars = nil; + _parseError = nil; + } + return self; +} + +- (void)dealloc { + [_stack release]; + [_nameStack release]; + [_rootObject release]; + [_rootName release]; + [_chars release]; + [_parseError release]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// NSXMLParserDelegate + +- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName + namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName + attributes:(NSDictionary *)attributeDict { + [self flushCharacters]; + + id object = nil; + if ([[attributeDict objectForKey:@"list"] isEqualToString:@"true"]) { + object = [NSMutableArray array]; + } else { + object = [NSNull null]; + } + + [_stack addObject:object]; + [_nameStack addObject:elementName]; +} + +- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { + if (!_chars) { + _chars = [string mutableCopy]; + } else { + [_chars appendString:string]; + } +} + +- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName + namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { + [self flushCharacters]; + + id object = [[[self topObject:NO] retain] autorelease]; + NSString* name = [[self.topName retain] autorelease]; + [_stack removeLastObject]; + [_nameStack removeLastObject]; + + if (!_stack.count) { + _rootObject = [object retain]; + _rootName = [name retain]; + } else { + id topObject = [self topObject:YES]; + if ([topObject isKindOfClass:[NSMutableArray class]]) { + [topObject addObject:object]; + } else if ([topObject isKindOfClass:[NSMutableDictionary class]]) { + [topObject setObject:object forKey:name]; + } + } +} + +- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)error { + _parseError = [error retain]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h new file mode 100644 index 00000000..18cbbde0 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h @@ -0,0 +1,52 @@ +// +// SHKFacebook.h +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" +#import "FBConnect.h" + +typedef enum +{ + SHKFacebookPendingNone, + SHKFacebookPendingLogin, + SHKFacebookPendingStatus, + SHKFacebookPendingImage +} SHKFacebookPendingAction; + + +@interface SHKFacebook : SHKSharer +{ + FBSession *session; + SHKFacebookPendingAction pendingAction; + FBLoginDialog *login; +} + +@property (retain) FBSession *session; +@property SHKFacebookPendingAction pendingAction; +@property (retain) FBLoginDialog *login; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m new file mode 100644 index 00000000..5e5fdf39 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -0,0 +1,218 @@ +// +// SHKFacebook.m +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKFacebook.h" + + +@implementation SHKFacebook + +@synthesize session; +@synthesize pendingAction; +@synthesize login; + + +- (void)dealloc +{ + [session.delegates removeObject:self]; + [session release]; + [login release]; + [super dealloc]; +} + + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Facebook"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + ++ (BOOL)canShareImage +{ + return YES; +} + ++ (BOOL)canShareOffline +{ + return NO; // TODO - would love to make this work +} + + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + +- (BOOL)shouldAutoShare +{ + return YES; // FBConnect presents its own dialog +} + + + +#pragma mark - +#pragma mark Authentication + +- (BOOL)isAuthorized +{ + if (session == nil) + { + self.session = [FBSession sessionForApplication:SHKFacebookKey + secret:SHKFacebookSecret + delegate:self]; + return [session resume]; + } + + return [session isConnected]; +} + +- (void)promptAuthorization +{ + self.pendingAction = SHKFacebookPendingLogin; + self.login = [[[FBLoginDialog alloc] init] autorelease]; + [login show]; +} + +- (void)authFinished:(SHKRequest *)request +{ + +} + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send +{ + if (item.shareType == SHKShareTypeURL) + { + self.pendingAction = SHKFacebookPendingStatus; + + FBStreamDialog* dialog = [[[FBStreamDialog alloc] init] autorelease]; + dialog.delegate = self; + dialog.userMessagePrompt = @"Enter your message:"; + dialog.attachment = [NSString stringWithFormat: + @"{\ + \"name\":\"%@\",\ + \"href\":\"%@\"\ + }", + item.title == nil ? SHKEncodeURL(item.URL) : SHKEncode(item.title), + SHKEncodeURL(item.URL) + ]; + dialog.actionLinks = [NSString stringWithFormat:@"[{\"text\":\"Get %@\",\"href\":\"%@\"}]", + SHKEncode(SHKMyAppName), + SHKEncode(SHKMyAppURL)]; + [dialog show]; + + } + + else if (item.shareType == SHKShareTypeImage) + { + self.pendingAction = SHKFacebookPendingImage; + + FBPermissionDialog* dialog = [[[FBPermissionDialog alloc] init] autorelease]; + dialog.delegate = self; + dialog.permission = @"photo_upload"; + [dialog show]; + } + + return YES; +} + +- (void)sendImage +{ + [self sendDidStart]; + + [[FBRequest requestWithDelegate:self] call:@"facebook.photos.upload" + params:[NSDictionary dictionaryWithObjectsAndKeys:item.title, @"caption", nil] + dataParam:UIImageJPEGRepresentation(item.image,100)]; +} + +- (void)dialogDidSucceed:(FBDialog*)dialog +{ + if (pendingAction == SHKFacebookPendingImage) + [self sendImage]; + + // TODO - the dialog has a SKIP button. Skipping still calls this even though it doesn't appear to post. + // - need to intercept the skip and handle it as a cancel? + else if (pendingAction == SHKFacebookPendingStatus) + [self sendDidFinish]; +} + +- (void)dialogDidCancel:(FBDialog*)dialog +{ + if (pendingAction == SHKFacebookPendingStatus) + [self sendDidCancel]; +} + +- (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url +{ + return YES; +} + + +#pragma mark FBSessionDelegate methods + +- (void)session:(FBSession*)session didLogin:(FBUID)uid +{ + // Try to share again + if (pendingAction == SHKFacebookPendingLogin) + { + self.pendingAction = SHKFacebookPendingNone; + [self share]; + } +} + +- (void)session:(FBSession*)session willLogout:(FBUID)uid +{ + // Not handling this +} + + +#pragma mark FBRequestDelegate methods + +- (void)request:(FBRequest*)aRequest didLoad:(id)result +{ + if ([aRequest.method isEqualToString:@"facebook.photos.upload"]) + { + // PID is in [result objectForKey:@"pid"]; + [self sendDidFinish]; + } +} + +- (void)request:(FBRequest*)aRequest didFailWithError:(NSError*)error +{ + [self sendDidFailWithError:error]; +} + + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.h b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.h new file mode 100644 index 00000000..9ac34068 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.h @@ -0,0 +1,44 @@ +// +// SHKGoogleReader.h +// ShareKit +// +// Created by Nathan Weiner on 6/20/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" + +@interface SHKGoogleReader : SHKSharer +{ + NSMutableDictionary *session; + BOOL sendAfterLogin; +} + +@property (nonatomic, retain) NSMutableDictionary *session; +@property (nonatomic) BOOL sendAfterLogin; + +- (void)sendWithToken:(NSString *)token; +- (void)getSession:(NSString *)email password:(NSString *)password; +- (void)signRequest:(SHKRequest *)aRequest; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m new file mode 100644 index 00000000..cc90ec4c --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m @@ -0,0 +1,301 @@ +// +// SHKGoogleReader.m +// ShareKit +// +// Created by Nathan Weiner on 6/20/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + + +/* + +Google Reader API is unoffical, this was hobbled together from: + http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI + http://stackoverflow.com/questions/1041389/adding-notes-using-google-readers-api + http://www.google.com/support/reader/bin/answer.py?hl=en&answer=147149 +*/ + + +#import "SHKGoogleReader.h" + + +@implementation SHKGoogleReader + +@synthesize session; +@synthesize sendAfterLogin; + + +- (void)dealloc +{ + [session release]; + [super dealloc]; +} + + + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Google Reader"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + + + +#pragma mark - +#pragma mark Authorization + +- (NSString *)authorizationFormCaption +{ + return @"Set up a free account at http://google.com/reader"; +} + +- (NSArray *)authorizationFormFields +{ + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Email" key:@"email" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:@"Password" key:@"password" type:SHKFormFieldTypePassword start:nil], + nil]; +} + +- (void)authorizationFormValidate:(SHKFormController *)form +{ + // Display an activity indicator + if (!quiet) + [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + + + // Authorize the user through the server + NSDictionary *formValues = [form formValues]; + + [self getSession:[formValues objectForKey:@"email"] + password:[formValues objectForKey:@"password"]]; + + self.pendingForm = form; +} + +- (void)getSession:(NSString *)email password:(NSString *)password +{ + NSString *params = [NSMutableString stringWithFormat:@"service=reader&source=%@&Email=%@&Passwd=%@&accountType=GOOGLE", + [NSString stringWithFormat:@"ShareKit-%@-%@", SHKEncode(SHKMyAppName), SHK_VERSION], + SHKEncode(email), + SHKEncode(password) + ]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.google.com/accounts/ClientLogin"] + params:params + delegate:self + isFinishedSelector:@selector(authFinished:) + method:@"POST" + autostart:YES] autorelease]; +} + +- (void)authFinished:(SHKRequest *)aRequest +{ + // TODO - better error handling - use error codes from ( http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html ) + // TODO - capatcha support + + // Hide the activity indicator + if (!sendAfterLogin) + [[SHKActivityIndicator currentIndicator] hide]; + + // Parse Result + self.session = [NSMutableDictionary dictionaryWithCapacity:0]; + NSString *result = [request getResult]; + NSArray *parts; + + if (result != nil) + { + NSArray *lines = [result componentsSeparatedByString:@"\n"]; + for( NSString *line in lines) + { + parts = [line componentsSeparatedByString:@"="]; + if (parts.count == 2) + [session setObject:[parts objectAtIndex:1] forKey:[parts objectAtIndex:0]]; + } + } + + if (session != nil && [session objectForKey:@"Auth"]) + { + if (sendAfterLogin) + [self tryToSend]; + + else + [pendingForm saveForm]; + } + + else + { + NSString *error = [session objectForKey:@"Error"]; + NSString *message = nil; + + if (error != nil) + message = [error isEqualToString:@"BadAuthentication"] ? @"Incorrect username and password" : error; + + if (message == nil) // TODO - Could use some clearer message here. + message = @"There was an error logging into Google Reader"; + + [[[[UIAlertView alloc] initWithTitle:@"Login Error" + message:message + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + } +} + + +#pragma mark - +#pragma mark Share Form + +- (NSArray *)shareFormFieldsForType:(SHKShareType)type +{ + if (type == SHKShareTypeURL) + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Note" key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:@"Public" key:@"share" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + nil]; + + return nil; +} + + +#pragma mark - +#pragma mark Share API Methods + +- (void)signRequest:(SHKRequest *)aRequest +{ + // Add session cookie + NSDictionary *cookieDictionary; + NSHTTPCookie *cookie; + NSMutableArray *cookies = [NSMutableArray arrayWithCapacity:0]; + for (NSString *cookieName in session) + { + + cookieDictionary = [NSDictionary dictionaryWithObjectsAndKeys: + cookieName, NSHTTPCookieName, + [session objectForKey:cookieName], NSHTTPCookieValue, + @".google.com", NSHTTPCookieDomain, + @"/", NSHTTPCookiePath, + [NSDate dateWithTimeIntervalSinceNow:1600000000], NSHTTPCookieExpires, + nil]; + cookie = [NSHTTPCookie cookieWithProperties:cookieDictionary]; + [cookies addObject:cookie]; + } + NSMutableDictionary *headers = [[[NSHTTPCookie requestHeaderFieldsWithCookies:cookies] mutableCopy] autorelease]; + + [headers setObject:[NSString stringWithFormat:@"GoogleLogin auth=%@",[session objectForKey:@"Auth"]] forKey:@"Authorization"]; + + [aRequest setHeaderFields:headers]; +} + +- (BOOL)send +{ + if ([self validateItem]) + { + BOOL sentAfterLogin = sendAfterLogin; + + if (session == nil) + { + // Login first + self.sendAfterLogin = YES; + [self getSession:[self getAuthValueForKey:@"email"] + password:[self getAuthValueForKey:@"password"]]; + } + + else + { + + self.sendAfterLogin = NO; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString: + [NSString stringWithFormat: + @"http://www.google.com/reader/api/0/token?ck=%i", + [[NSDate date] timeIntervalSince1970] + ]] + params:nil + delegate:self + isFinishedSelector:@selector(tokenFinished:) + method:@"GET" + autostart:NO] autorelease]; + [self signRequest:request]; + [request start]; + } + + // Notify delegate + if (!sentAfterLogin) + [self sendDidStart]; + + return YES; + } + + return NO; +} + +- (void)tokenFinished:(SHKRequest *)aRequest +{ + if (aRequest.success) + [self sendWithToken:[request getResult]]; + + else + [self sendDidFailWithError:[SHK error:@"There was a problem authenticating your account."]]; // TODO better error handling/message +} + +- (void)sendWithToken:(NSString *)token +{ + NSString *params = [NSMutableString stringWithFormat:@"T=%@&linkify=false&snippet=%@&srcTitle=%@&srcUrl=%@&title=%@&url=%@&share=%@", + token, + SHKEncode(item.text), + SHKEncode(SHKMyAppName), + SHKEncode(SHKMyAppURL), + SHKEncode(item.title), + SHKEncodeURL(item.URL), + [item customBoolForSwitchKey:@"share"]?@"true":@"" + ]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.google.com/reader/api/0/item/edit"] + params:params + delegate:self + isFinishedSelector:@selector(sendFinished:) + method:@"POST" + autostart:NO] autorelease]; + + [self signRequest:request]; + [request start]; +} + +- (void)sendFinished:(SHKRequest *)aRequest +{ + if (aRequest.success) + [self sendDidFinish]; + + else + [self sendDidFailWithError:[SHK error:@"There was a problem saving your note."]]; // TODO better error handling/message +} + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.h b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.h new file mode 100644 index 00000000..6995bb28 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.h @@ -0,0 +1,36 @@ +// +// SHKPinboard.h +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" + +@interface SHKPinboard : SHKSharer +{ + +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m new file mode 100644 index 00000000..24f864c5 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m @@ -0,0 +1,173 @@ +// +// SHKPinboard.m +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKPinboard.h" + + +@implementation SHKPinboard + + + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Pinboard"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + + +#pragma mark - +#pragma mark Authorization + +- (NSString *)authorizationFormCaption +{ + return @"Set up an account at http://pinboard.in"; +} + +- (void)authorizationFormValidate:(SHKFormController *)form +{ + // Display an activity indicator + if (!quiet) + [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + + + // Authorize the user through the server + NSDictionary *formValues = [form formValues]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString: + [NSString stringWithFormat:@"https://%@:%@@api.pinboard.in/v1/posts/get", + SHKEncode([formValues objectForKey:@"username"]), + SHKEncode([formValues objectForKey:@"password"]) + ]] + params:nil + delegate:self + isFinishedSelector:@selector(authFinished:) + method:@"POST" + autostart:YES] autorelease]; + + self.pendingForm = form; +} + +- (BOOL)handleResponse:(SHKRequest *)aRequest +{ + NSString *response = [aRequest getResult]; + + if ([response isEqualToString:@"401 Forbidden"]) + { + [self sendDidFailShouldRelogin]; + return NO; + } + + return YES; +} + +- (void)authFinished:(SHKRequest *)aRequest +{ + // Hide the activity indicator + [[SHKActivityIndicator currentIndicator] hide]; + + if ([self handleResponse:aRequest]) + { + [pendingForm saveForm]; + } +} + + +#pragma mark - +#pragma mark Share Form + +- (NSArray *)shareFormFieldsForType:(SHKShareType)type +{ + if (type == SHKShareTypeURL) + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Title" key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:@"Tags" key:@"tags" type:SHKFormFieldTypeText start:item.tags], + [SHKFormFieldSettings label:@"Notes" key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:@"Shared" key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + nil]; + + return nil; +} + + + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send +{ + if ([self validateItem]) + { + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString: + [NSString stringWithFormat:@"https://%@:%@@api.pinboard.in/v1/posts/add?url=%@&description=%@&tags=%@&extended=%@&shared=%@", + SHKEncode([self getAuthValueForKey:@"username"]), + SHKEncode([self getAuthValueForKey:@"password"]), + SHKEncodeURL(item.URL), + SHKEncode(item.title), + SHKEncode(item.tags), + SHKEncode(item.text), + [item customBoolForSwitchKey:@"shared"]?@"yes":@"no" + ]] + params:nil + delegate:self + isFinishedSelector:@selector(sendFinished:) + method:@"GET" + autostart:YES] autorelease]; + + + // Notify delegate + [self sendDidStart]; + + return YES; + } + + return NO; +} + +- (void)sendFinished:(SHKRequest *)aRequest +{ + if ([self handleResponse:aRequest]) + { + // TODO parse +#import "SHKSharer.h" + +@interface SHKReadItLater : SHKSharer +{ +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m b/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m new file mode 100644 index 00000000..9df5880e --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m @@ -0,0 +1,188 @@ + // +// SHKReadItLater.m +// ShareKit +// +// Created by Nathan Weiner on 6/8/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +// SHOULD FUNCS - can these be implemented like dataSource and delegate on tableview? + +#import "SHKReadItLater.h" + + +@implementation SHKReadItLater + + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Read It Later"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + +// Though manual sharing is supported (by changing removing this subclass), one tap to save is the ideal 'read later' behavior +- (BOOL)shouldAutoShare +{ + return YES; +} + + + +#pragma mark - +#pragma mark Authorization + +- (NSString *)authorizationFormCaption +{ + return @"Set up a free account at http://readitlaterlist.com"; +} + +- (void)authorizationFormValidate:(SHKFormController *)form +{ + // Display an activity indicator + if (!quiet) + [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + + + // Authorize the user through the server + NSDictionary *formValues = [form formValues]; + + NSString *params = [NSMutableString stringWithFormat:@"apikey=%@&username=%@&password=%@", + SHKReadItLaterKey, + SHKEncode([formValues objectForKey:@"username"]), + SHKEncode([formValues objectForKey:@"password"]) + ]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:@"http://readitlaterlist.com/v2/auth"] + params:params + delegate:self + isFinishedSelector:@selector(authFinished:) + method:@"POST" + autostart:YES] autorelease]; + + self.pendingForm = form; +} + +- (void)authFinished:(SHKRequest *)aRequest +{ + // Hide the activity indicator + [[SHKActivityIndicator currentIndicator] hide]; + + if (aRequest.success) + [pendingForm saveForm]; + + else + { + [[[[UIAlertView alloc] initWithTitle:@"Login Error" + message:[request.headers objectForKey:@"X-Error"] + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + } +} + + + +#pragma mark - +#pragma mark Share Form + +- (NSArray *)shareFormFieldsForType:(SHKShareType)type +{ + if (type == SHKShareTypeURL) + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Title" key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:@"Tags" key:@"tags" type:SHKFormFieldTypeText start:item.tags], + nil]; + + return nil; +} + + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send +{ + if ([self validateItem]) + { + NSString *new = [NSString stringWithFormat:@"&new={\"0\":{\"url\":\"%@\",\"title\":\"%@\"}}", + SHKEncodeURL(item.URL), + SHKEncode(item.title)]; + + NSString *tags = item.tags == nil || !item.tags.length ? @"" : + [NSString stringWithFormat:@"&update_tags={\"0\":{\"url\":\"%@\",\"tags\":\"%@\"}}", + SHKEncodeURL(item.URL), SHKEncode(item.tags)]; + + NSString *params = [NSMutableString stringWithFormat:@"apikey=%@&username=%@&password=%@%@%@", + SHKReadItLaterKey, + SHKEncode([self getAuthValueForKey:@"username"]), + SHKEncode([self getAuthValueForKey:@"password"]), + new, + tags]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:@"http://readitlaterlist.com/v2/send"] + params:params + delegate:self + isFinishedSelector:@selector(sendFinished:) + method:@"POST" + autostart:YES] autorelease]; + + + // Notify delegate + [self sendDidStart]; + + return YES; + } + + return NO; +} + +- (void)sendFinished:(SHKRequest *)aRequest +{ + if (!aRequest.success) + { + if (aRequest.response.statusCode == 401) + { + [self sendDidFailShouldRelogin]; + return; + } + + [self sendDidFailWithError:[SHK error:[request.headers objectForKey:@"X-Error"]]]; + return; + } + + [self sendDidFinish]; +} + + + +@end diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h new file mode 100644 index 00000000..2dce32ef --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h @@ -0,0 +1,61 @@ +// +// SHKTwitter.h +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKOAuthSharer.h" +#import "SHKTwitterForm.h" + +@interface SHKTwitter : SHKOAuthSharer +{ + BOOL xAuth; + NSString *myTwitterUsername; +} + +@property BOOL xAuth; +@property (nonatomic, retain) NSString *myTwitterUsername; + + +#pragma mark - +#pragma mark UI Implementation + +- (void)showTwitterForm; + +#pragma mark - +#pragma mark Share API Methods + +- (void)shortenURL; +- (void)shortenURLFinished:(SHKRequest *)aRequest; + +- (void)sendForm:(SHKTwitterForm *)form; + +- (void)sendStatus; +- (void)sendStatusTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data; +- (void)sendStatusTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error; + +- (void)followMe; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m new file mode 100644 index 00000000..b22e2544 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -0,0 +1,379 @@ +// +// SHKTwitter.m +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +// TODO - SHKTwitter supports offline sharing, however the url cannot be shortened without an internet connection. Need a graceful workaround for this. + + +#import "SHKTwitter.h" + +@implementation SHKTwitter + +@synthesize xAuth; +@synthesize myTwitterUsername; + +- (void)dealloc +{ + [myTwitterUsername release]; + [super dealloc]; +} + +- (id)init +{ + if (self = [super init]) + { + // Enter your app's twitter account if you'd like to ask the user to follow it when logging in + self.myTwitterUsername = [SHKTwitterUsername isEqualToString:@""] ? nil : SHKTwitterUsername; + + // OAUTH + self.consumerKey = SHKTwitterConsumerKey; + self.secretKey = SHKTwitterSecret; + self.authorizeCallbackURL = [NSURL URLWithString:SHKTwitterCallbackUrl];// HOW-TO: In your Twitter application settings, use the "Callback URL" field. If you do not have this field in the settings, set your application type to 'Browser'. + + // XAUTH + self.xAuth = SHKTwitterUseXAuth?YES:NO; + + + // -- // + + + // You do not need to edit these, they are the same for everyone + self.authorizeURL = [NSURL URLWithString:@"https://twitter.com/oauth/authorize"]; + self.requestURL = [NSURL URLWithString:@"https://twitter.com/oauth/request_token"]; + self.accessURL = [NSURL URLWithString:@"https://twitter.com/oauth/access_token"]; + } + return self; +} + + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Twitter"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + ++ (BOOL)canShareText +{ + return YES; +} + +// TODO use img.ly to support this +//+ (BOOL)canShareImage +//{ +// return YES; +//} + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + +- (BOOL)shouldAutoShare +{ + return NO; +} + + +#pragma mark - +#pragma mark Authorization + +- (BOOL)isAuthorized +{ + return [self restoreAccessToken]; +} + +- (void)promptAuthorization +{ + if (xAuth) + [super authorizationFormShow]; // xAuth process + + else + [super promptAuthorization]; // OAuth process +} + + +#pragma mark xAuth + +- (NSString *)authorizationFormCaption +{ + return @"Sign up for a free account at http://twitter.com"; +} + +- (NSArray *)authorizationFormFields +{ + if (myTwitterUsername == nil) + return [super authorizationFormFields]; + + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Username" key:@"username" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:@"Password" key:@"password" type:SHKFormFieldTypePassword start:nil], + [SHKFormFieldSettings label:[NSString stringWithFormat:@"Follow %@",myTwitterUsername] key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], + nil]; +} + +- (void)authorizationFormValidate:(SHKFormController *)form +{ + self.pendingForm = form; + [self tokenAccess]; +} + +- (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest +{ + if (xAuth) + { + NSDictionary *formValues = [pendingForm formValues]; + + OARequestParameter *username = [[[OARequestParameter alloc] initWithName:@"x_auth_username" + value:SHKEncode([formValues objectForKey:@"username"])] autorelease]; + + OARequestParameter *password = [[[OARequestParameter alloc] initWithName:@"x_auth_password" + value:SHKEncode([formValues objectForKey:@"password"])] autorelease]; + + OARequestParameter *mode = [[[OARequestParameter alloc] initWithName:@"x_auth_mode" + value:@"client_auth"] autorelease]; + + [oRequest setParameters:[NSArray arrayWithObjects:username, password, mode, nil]]; + } +} + +- (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data +{ + if (xAuth) + { + if (ticket.didSucceed) + { + [item setCustomValue:[[pendingForm formValues] objectForKey:@"followMe"] forKey:@"followMe"]; + [pendingForm close]; + } + + else + { + [self tokenAccessTicket:ticket didFailWithError:[SHK error:[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]]]; + return; + } + } + + [super tokenAccessTicket:ticket didFinishWithData:data]; +} + + +#pragma mark - +#pragma mark UI Implementation + +- (void)show +{ + if (item.shareType == SHKShareTypeURL) + { + [self shortenURL]; + } + + else if (item.shareType == SHKShareTypeImage) + { + [item setCustomValue:item.title forKey:@"status"]; + [self showTwitterForm]; + } + + else if (item.shareType == SHKShareTypeText) + { + [item setCustomValue:item.text forKey:@"status"]; + [self showTwitterForm]; + } +} + +- (void)showTwitterForm +{ + SHKTwitterForm *rootView = [[SHKTwitterForm alloc] initWithNibName:nil bundle:nil]; + rootView.delegate = self; + + // force view to load so we can set textView text + [rootView view]; + + rootView.textView.text = [item customValueForKey:@"status"]; + rootView.hasAttachment = item.image != nil; + + [self pushViewController:rootView animated:NO]; + + [[SHK currentHelper] showViewController:self]; +} + +- (void)sendForm:(SHKTwitterForm *)form +{ + [item setCustomValue:form.textView.text forKey:@"status"]; + [self tryToSend]; +} + + +#pragma mark - + +- (void)shortenURL +{ + if (!quiet) + [[SHKActivityIndicator currentIndicator] displayActivity:@"Shortening URL..."]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:[NSMutableString stringWithFormat:@"http://api.bit.ly/v3/shorten?login=%@&apikey=%@&longUrl=%@&format=txt", + SHKBitLyLogin, + SHKBitLyKey, + SHKEncodeURL(item.URL) + ]] + params:nil + delegate:self + isFinishedSelector:@selector(shortenURLFinished:) + method:@"GET" + autostart:YES] autorelease]; +} + +- (void)shortenURLFinished:(SHKRequest *)aRequest +{ + [[SHKActivityIndicator currentIndicator] hide]; + + NSString *result = [[aRequest getResult] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + + if ([result rangeOfString:@"http://bit.ly"].location == NSNotFound) + { + // TODO - better error message + [[[[UIAlertView alloc] initWithTitle:@"Shorten URL Error" + message:@"We could not shorten the URL." + delegate:nil + cancelButtonTitle:@"Continue" + otherButtonTitles:nil] autorelease] show]; + + [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.title, [item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] forKey:@"status"]; + } + + else + [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.title, result] forKey:@"status"]; + + [self showTwitterForm]; +} + + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)validate +{ + NSString *status = [item customValueForKey:@"status"]; + return status != nil && status.length >= 0 && status.length <= 140; +} + +- (BOOL)send +{ + // Check if we should send follow request too + if (xAuth && [item customBoolForSwitchKey:@"followMe"]) + [self followMe]; + + if (![self validate]) + [self show]; + + else + { + //if (item.shareType == SHKShareTypeImage) + // [self sendImage]; + + //else + [self sendStatus]; + + + // Notify delegate + [self sendDidStart]; + + return YES; + } + + return NO; +} + +- (void)sendStatus +{ + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.twitter.com/1/statuses/update.json"] + consumer:consumer + token:accessToken + realm:nil + signatureProvider:nil]; + + [oRequest setHTTPMethod:@"POST"]; + + OARequestParameter *statusParam = [[OARequestParameter alloc] initWithName:@"status" + value:[item customValueForKey:@"status"]]; + NSArray *params = [NSArray arrayWithObjects:statusParam, nil]; + [oRequest setParameters:params]; + [statusParam release]; + + OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest + delegate:self + didFinishSelector:@selector(sendStatusTicket:didFinishWithData:) + didFailSelector:@selector(sendStatusTicket:didFailWithError:)]; + + [fetcher start]; + [oRequest release]; +} + +- (void)sendStatusTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data +{ + // TODO better error handling here + + if (ticket.didSucceed) + [self sendDidFinish]; + + else + [self sendDidFailWithError:nil]; +} + +- (void)sendStatusTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error +{ + [self sendDidFailWithError:error]; +} + + +- (void)followMe +{ + // remove it so in case of other failures this doesn't get hit again + [item setCustomValue:nil forKey:@"followMe"]; + + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://api.twitter.com/1/friendships/create/%@.json", myTwitterUsername]] + consumer:consumer + token:accessToken + realm:nil + signatureProvider:nil]; + + [oRequest setHTTPMethod:@"POST"]; + + OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest + delegate:nil // Currently not doing any error handling here. If it fails, it's probably best not to bug the user to follow you again. + didFinishSelector:nil + didFailSelector:nil]; + + [fetcher start]; + [oRequest release]; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.h b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.h new file mode 100644 index 00000000..b31119d8 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.h @@ -0,0 +1,44 @@ +// +// SHKTwitterForm.h +// ShareKit +// +// Created by Nathan Weiner on 6/22/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface SHKTwitterForm : UIViewController +{ + id delegate; + UITextView *textView; + UILabel *counter; + BOOL hasAttachment; +} + +@property (nonatomic, retain) id delegate; +@property (nonatomic, retain) UITextView *textView; +@property (nonatomic, retain) UILabel *counter; +@property BOOL hasAttachment; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m new file mode 100644 index 00000000..a6932e71 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m @@ -0,0 +1,212 @@ + // +// SHKTwitterForm.m +// ShareKit +// +// Created by Nathan Weiner on 6/22/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKTwitterForm.h" +#import "SHK.h" +#import "SHKTwitter.h" + + +@implementation SHKTwitterForm + +@synthesize delegate; +@synthesize textView; +@synthesize counter; +@synthesize hasAttachment; + +- (void)dealloc +{ + [delegate release]; + [textView release]; + [counter release]; + [super dealloc]; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) + { + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(cancel)]; + + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Send to Twitter" + style:UIBarButtonItemStyleDone + target:self + action:@selector(save)]; + } + return self; +} + + + +- (void)loadView +{ + [super loadView]; + + self.view.backgroundColor = [UIColor whiteColor]; + + self.textView = [[UITextView alloc] initWithFrame:CGRectZero]; + textView.delegate = self; + textView.font = [UIFont systemFontOfSize:15]; + textView.contentInset = UIEdgeInsetsMake(5,5,0,0); + textView.backgroundColor = [UIColor whiteColor]; + textView.autoresizesSubviews = YES; + textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + [self.view addSubview:textView]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self selector:@selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil]; + + [self.textView becomeFirstResponder]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + // Remove observers + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self name: UIKeyboardWillShowNotification object:nil]; + + // Remove the SHK view wrapper from the window + [[SHK currentHelper] viewWasDismissed]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + +- (void)keyboardWillShow:(NSNotification *)notification +{ + CGRect keyboardFrame; + CGFloat keyboardHeight; + + // 3.2 and above + /*if (UIKeyboardFrameEndUserInfoKey) + { + [[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrame]; + if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) + keyboardHeight = keyboardFrame.size.height; + else + keyboardHeight = keyboardFrame.size.width; + } + + // < 3.2 + else + {*/ + [[notification.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame]; + keyboardHeight = keyboardFrame.size.height; + //} + + textView.frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height-keyboardHeight); +} + +#pragma mark - + +- (void)updateCounter +{ + if (counter == nil) + { + self.counter = [[UILabel alloc] initWithFrame:CGRectMake(textView.bounds.size.width-150-15, + textView.bounds.size.height-15-9, + 150, + 15)]; + counter.backgroundColor = [UIColor clearColor]; + counter.opaque = NO; + counter.font = [UIFont boldSystemFontOfSize:14]; + counter.textAlignment = UITextAlignmentRight; + + counter.autoresizesSubviews = YES; + counter.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin; + + [self.view addSubview:counter]; + + [counter release]; + } + + int count = (hasAttachment?115:140) - textView.text.length; + counter.text = [NSString stringWithFormat:@"%@%i", hasAttachment ? @"Image + ":@"" , count]; + counter.textColor = count >= 0 ? [UIColor blackColor] : [UIColor redColor]; +} + +- (void)textViewDidBeginEditing:(UITextView *)textView +{ + [self updateCounter]; +} + +- (void)textViewDidChange:(UITextView *)textView +{ + [self updateCounter]; +} + +- (void)textViewDidEndEditing:(UITextView *)textView +{ + [self updateCounter]; +} + +#pragma mark - + +- (void)cancel +{ + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; +} + +- (void)save +{ + if (textView.text.length > (hasAttachment?115:140)) + { + [[[[UIAlertView alloc] initWithTitle:@"Message is too long" + message:@"Twitter posts can only be 140 characters in length." + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + return; + } + + else if (textView.text.length == 0) + { + [[[[UIAlertView alloc] initWithTitle:@"Message is empty" + message:@"You must enter a message in order to post." + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + return; + } + + [(SHKTwitter *)delegate sendForm:self]; + + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; +} + +@end diff --git a/Classes/ShareKit/UI/SHKActionSheet.h b/Classes/ShareKit/UI/SHKActionSheet.h new file mode 100644 index 00000000..86e49301 --- /dev/null +++ b/Classes/ShareKit/UI/SHKActionSheet.h @@ -0,0 +1,46 @@ +// +// SHKActionSheet.h +// ShareKit +// +// Created by Nathan Weiner on 6/10/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHK.h" + +@interface SHKActionSheet : UIActionSheet +{ + NSArray *sharers; + + SHKItem *item; +} + +@property (retain) NSArray *sharers; + +@property (retain) SHKItem *item; + ++ (SHKActionSheet *)actionSheetForType:(SHKShareType)type; ++ (SHKActionSheet *)actionSheetForItem:(SHKItem *)i; +- (void)actionSheet:(SHKActionSheet *)as clickedButtonAtIndex:(NSInteger)buttonIndex; + +@end \ No newline at end of file diff --git a/Classes/ShareKit/UI/SHKActionSheet.m b/Classes/ShareKit/UI/SHKActionSheet.m new file mode 100644 index 00000000..a103c831 --- /dev/null +++ b/Classes/ShareKit/UI/SHKActionSheet.m @@ -0,0 +1,102 @@ +// +// SHKActionSheet.m +// ShareKit +// +// Created by Nathan Weiner on 6/10/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKActionSheet.h" +#import "SHK.h" +#import "SHKSharer.h" +#import "SHKCustomShareMenu.h" +#import + +@implementation SHKActionSheet + +@synthesize item, sharers; + +- (void)dealloc +{ + [item release]; + [sharers release]; + [super dealloc]; +} + ++ (SHKActionSheet *)actionSheetForType:(SHKShareType)type +{ + SHKActionSheet *as = [[SHKActionSheet alloc] initWithTitle:@"Share" + delegate:self + cancelButtonTitle:nil + destructiveButtonTitle:nil + otherButtonTitles:nil]; + as.item = [[[SHKItem alloc] init] autorelease]; + as.item.shareType = type; + as.delegate = as; + + as.sharers = [SHK favoriteSharersForType:type]; + + // Add buttons for each favoriate sharer + id class; + for(NSString *sharerId in as.sharers) + { + class = NSClassFromString(sharerId); + if ([class canShare]) + [as addButtonWithTitle: [class sharerTitle] ]; + } + + // Add More button + [as addButtonWithTitle:@"More..."]; + + // Add Cancel button + [as addButtonWithTitle:@"Cancel"]; + as.cancelButtonIndex = as.numberOfButtons -1; + + return [as autorelease]; +} + ++ (SHKActionSheet *)actionSheetForItem:(SHKItem *)i +{ + SHKActionSheet *as = [self actionSheetForType:i.shareType]; + as.item = i; + return as; +} + +- (void)actionSheet:(SHKActionSheet *)as clickedButtonAtIndex:(NSInteger)buttonIndex +{ + // Sharers + if (buttonIndex < as.sharers.count) + { + [objc_getClass([[as.sharers objectAtIndex:buttonIndex] UTF8String]) performSelector:@selector(shareItem:) withObject:item]; + } + + // More + else if (buttonIndex == as.sharers.count) + { + SHKShareMenu *shareMenu = [[SHKCustomShareMenu alloc] initWithStyle:UITableViewStyleGrouped]; + shareMenu.item = as.item; + [[SHK currentHelper] showViewController:shareMenu]; + [shareMenu release]; + } +} + +@end \ No newline at end of file diff --git a/Classes/ShareKit/UI/SHKActivityIndicator.h b/Classes/ShareKit/UI/SHKActivityIndicator.h new file mode 100644 index 00000000..122bd911 --- /dev/null +++ b/Classes/ShareKit/UI/SHKActivityIndicator.h @@ -0,0 +1,59 @@ +// +// SHKActivityIndicator.h +// ShareKit +// +// Created by Nathan Weiner on 6/16/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface SHKActivityIndicator : UIView +{ + UILabel *centerMessageLabel; + UILabel *subMessageLabel; + + UIActivityIndicatorView *spinner; +} + +@property (nonatomic, retain) UILabel *centerMessageLabel; +@property (nonatomic, retain) UILabel *subMessageLabel; + +@property (nonatomic, retain) UIActivityIndicatorView *spinner; + + ++ (SHKActivityIndicator *)currentIndicator; + +- (void)show; +- (void)hideAfterDelay; +- (void)hide; +- (void)hidden; +- (void)displayActivity:(NSString *)m; +- (void)displayCompleted:(NSString *)m; +- (void)setCenterMessage:(NSString *)message; +- (void)setSubMessage:(NSString *)message; +- (void)showSpinner; +- (void)setProperRotation; +- (void)setProperRotation:(BOOL)animated; + +@end diff --git a/Classes/ShareKit/UI/SHKActivityIndicator.m b/Classes/ShareKit/UI/SHKActivityIndicator.m new file mode 100644 index 00000000..baf3ee04 --- /dev/null +++ b/Classes/ShareKit/UI/SHKActivityIndicator.m @@ -0,0 +1,277 @@ +// +// SHKActivityIndicator.m +// ShareKit +// +// Created by Nathan Weiner on 6/16/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKActivityIndicator.h" +#import + +#define SHKdegreesToRadians(x) (M_PI * x / 180.0) + +@implementation SHKActivityIndicator + +@synthesize centerMessageLabel, subMessageLabel; +@synthesize spinner; + +static SHKActivityIndicator *currentIndicator = nil; + + ++ (SHKActivityIndicator *)currentIndicator +{ + if (currentIndicator == nil) + { + UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow]; + + CGFloat width = 160; + CGFloat height = 160; + CGRect centeredFrame = CGRectMake(round(keyWindow.bounds.size.width/2 - width/2), + round(keyWindow.bounds.size.height/2 - height/2), + width, + height); + + currentIndicator = [[SHKActivityIndicator alloc] initWithFrame:centeredFrame]; + + currentIndicator.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]; + currentIndicator.opaque = NO; + currentIndicator.alpha = 0; + + currentIndicator.layer.cornerRadius = 10; + + currentIndicator.userInteractionEnabled = NO; + currentIndicator.autoresizesSubviews = YES; + currentIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; + + [currentIndicator setProperRotation:NO]; + + [[NSNotificationCenter defaultCenter] addObserver:currentIndicator + selector:@selector(setProperRotation) + name:UIDeviceOrientationDidChangeNotification + object:nil]; + } + + return currentIndicator; +} + +#pragma mark - + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; + + [centerMessageLabel release]; + [subMessageLabel release]; + [spinner release]; + + [super dealloc]; +} + +#pragma mark Creating Message + +- (void)show +{ + if ([self superview] != [[UIApplication sharedApplication] keyWindow]) + [[[UIApplication sharedApplication] keyWindow] addSubview:self]; + + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hide) object:nil]; + + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:0.3]; + + self.alpha = 1; + + [UIView commitAnimations]; +} + +- (void)hideAfterDelay +{ + [self performSelector:@selector(hide) withObject:nil afterDelay:0.6]; +} + +- (void)hide +{ + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:0.4]; + [UIView setAnimationDelegate:self]; + [UIView setAnimationDidStopSelector:@selector(hidden)]; + + self.alpha = 0; + + [UIView commitAnimations]; +} + +- (void)persist +{ + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hide) object:nil]; + + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationBeginsFromCurrentState:YES]; + [UIView setAnimationDuration:0.1]; + + self.alpha = 1; + + [UIView commitAnimations]; +} + +- (void)hidden +{ + if (currentIndicator.alpha > 0) + return; + + [currentIndicator removeFromSuperview]; + currentIndicator = nil; +} + +- (void)displayActivity:(NSString *)m +{ + [self setSubMessage:m]; + [self showSpinner]; + + [centerMessageLabel removeFromSuperview]; + centerMessageLabel = nil; + + if ([self superview] == nil) + [self show]; + else + [self persist]; +} + +- (void)displayCompleted:(NSString *)m +{ + [self setCenterMessage:@"✓"]; + [self setSubMessage:m]; + + [spinner removeFromSuperview]; + spinner = nil; + + if ([self superview] == nil) + [self show]; + else + [self persist]; + + [self hideAfterDelay]; +} + +- (void)setCenterMessage:(NSString *)message +{ + if (message == nil && centerMessageLabel != nil) + self.centerMessageLabel = nil; + + else if (message != nil) + { + if (centerMessageLabel == nil) + { + self.centerMessageLabel = [[[UILabel alloc] initWithFrame:CGRectMake(12,round(self.bounds.size.height/2-50/2),self.bounds.size.width-24,50)] autorelease]; + centerMessageLabel.backgroundColor = [UIColor clearColor]; + centerMessageLabel.opaque = NO; + centerMessageLabel.textColor = [UIColor whiteColor]; + centerMessageLabel.font = [UIFont boldSystemFontOfSize:40]; + centerMessageLabel.textAlignment = UITextAlignmentCenter; + centerMessageLabel.shadowColor = [UIColor darkGrayColor]; + centerMessageLabel.shadowOffset = CGSizeMake(1,1); + centerMessageLabel.adjustsFontSizeToFitWidth = YES; + + [self addSubview:centerMessageLabel]; + } + + centerMessageLabel.text = message; + } +} + +- (void)setSubMessage:(NSString *)message +{ + if (message == nil && subMessageLabel != nil) + self.subMessageLabel = nil; + + else if (message != nil) + { + if (subMessageLabel == nil) + { + self.subMessageLabel = [[[UILabel alloc] initWithFrame:CGRectMake(12,self.bounds.size.height-45,self.bounds.size.width-24,30)] autorelease]; + subMessageLabel.backgroundColor = [UIColor clearColor]; + subMessageLabel.opaque = NO; + subMessageLabel.textColor = [UIColor whiteColor]; + subMessageLabel.font = [UIFont boldSystemFontOfSize:17]; + subMessageLabel.textAlignment = UITextAlignmentCenter; + subMessageLabel.shadowColor = [UIColor darkGrayColor]; + subMessageLabel.shadowOffset = CGSizeMake(1,1); + subMessageLabel.adjustsFontSizeToFitWidth = YES; + + [self addSubview:subMessageLabel]; + } + + subMessageLabel.text = message; + } +} + +- (void)showSpinner +{ + if (spinner == nil) + { + self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + + spinner.frame = CGRectMake(round(self.bounds.size.width/2 - spinner.frame.size.width/2), + round(self.bounds.size.height/2 - spinner.frame.size.height/2), + spinner.frame.size.width, + spinner.frame.size.height); + [spinner release]; + } + + [self addSubview:spinner]; + [spinner startAnimating]; +} + +#pragma mark - +#pragma mark Rotation + +- (void)setProperRotation +{ + [self setProperRotation:YES]; +} + +- (void)setProperRotation:(BOOL)animated +{ + UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; + + if (animated) + { + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:0.3]; + } + + if (orientation == UIDeviceOrientationPortraitUpsideDown) + self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, SHKdegreesToRadians(180)); + + else if (orientation == UIDeviceOrientationLandscapeLeft) + self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, SHKdegreesToRadians(90)); + + else if (orientation == UIDeviceOrientationLandscapeRight) + self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, SHKdegreesToRadians(-90)); + + if (animated) + [UIView commitAnimations]; +} + + +@end diff --git a/Classes/ShareKit/UI/SHKFormController.h b/Classes/ShareKit/UI/SHKFormController.h new file mode 100644 index 00000000..2d7fa35b --- /dev/null +++ b/Classes/ShareKit/UI/SHKFormController.h @@ -0,0 +1,82 @@ +// +// SHKFormController.h +// ShareKit +// +// Created by Nathan Weiner on 6/17/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKFormFieldSettings.h" +#import "SHKCustomFormFieldCell.h" + +@interface SHKFormController : UITableViewController +{ + id delegate; + SEL validateSelector; + SEL saveSelector; + + NSMutableArray *sections; + NSMutableDictionary *values; + + CGFloat labelWidth; + + UITextField *activeField; + + BOOL autoSelect; +} + +@property (retain) id delegate; +@property SEL validateSelector; +@property SEL saveSelector; + +@property (retain) NSMutableArray *sections; +@property (retain) NSMutableDictionary *values; + +@property CGFloat labelWidth; + +@property (nonatomic, retain) UITextField *activeField; + +@property BOOL autoSelect; + + +- (id)initWithStyle:(UITableViewStyle)style title:(NSString *)barTitle rightButtonTitle:(NSString *)rightButtonTitle; +- (void)addSection:(NSArray *)fields header:(NSString *)header footer:(NSString *)footer; + +#pragma mark - + +- (SHKFormFieldSettings *)rowSettingsForIndexPath:(NSIndexPath *)indexPath; + +#pragma mark - +#pragma mark Completion + +- (void)close; +- (void)cancel; +- (void)validateForm; +- (void)saveForm; + +#pragma mark - + +- (NSMutableDictionary *)formValues; +- (NSMutableDictionary *)formValuesForSection:(int)section; + +@end diff --git a/Classes/ShareKit/UI/SHKFormController.m b/Classes/ShareKit/UI/SHKFormController.m new file mode 100644 index 00000000..6d687432 --- /dev/null +++ b/Classes/ShareKit/UI/SHKFormController.m @@ -0,0 +1,288 @@ +// +// SHKFormController.m +// ShareKit +// +// Created by Nathan Weiner on 6/17/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHK.h" +#import "SHKCustomFormController.h" +#import "SHKCustomFormFieldCell.h" + + +@implementation SHKFormController + +@synthesize delegate, validateSelector, saveSelector; +@synthesize sections, values; +@synthesize labelWidth; +@synthesize activeField; +@synthesize autoSelect; + + +- (void)dealloc +{ + [delegate release]; + [sections release]; + [values release]; + [activeField release]; + + [super dealloc]; +} + + +#pragma mark - +#pragma mark Initialization + +- (id)initWithStyle:(UITableViewStyle)style title:(NSString *)barTitle rightButtonTitle:(NSString *)rightButtonTitle +{ + if (self = [super initWithStyle:style]) + { + self.title = barTitle; + + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(cancel)]; + + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:rightButtonTitle + style:UIBarButtonItemStyleDone + target:self + action:@selector(validateForm)]; + + self.values = [NSMutableDictionary dictionaryWithCapacity:0]; + } + return self; +} + +- (void)addSection:(NSArray *)fields header:(NSString *)header footer:(NSString *)footer +{ + if (sections == nil) + self.sections = [NSMutableArray arrayWithCapacity:0]; + + NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:0]; + [dict setObject:fields forKey:@"rows"]; + + if (header) + [dict setObject:header forKey:@"header"]; + + if (footer) + [dict setObject:footer forKey:@"footer"]; + + + [sections addObject:dict]; + + // Find the max length of the labels so we can use this value to align the left side of all form fields + // TODO - should probably save this per section for flexibility + if (sections.count == 1) + { + CGFloat newWidth = 0; + CGSize size; + + for (SHKFormFieldSettings *field in fields) + { + // only use text field rows + if (field.type != SHKFormFieldTypeText && field.type != SHKFormFieldTypePassword) + continue; + + size = [field.label sizeWithFont:[UIFont boldSystemFontOfSize:17]]; + if (size.width > newWidth) + newWidth = size.width; + } + + self.labelWidth = newWidth; + } +} + +#pragma mark - + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + if (autoSelect) + [self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone]; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + // Remove the SHK view wrapper from the window + [[SHK currentHelper] viewWasDismissed]; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + if (SHKFormBgColorRed != -1) + self.tableView.backgroundColor = [UIColor colorWithRed:SHKFormBgColorRed/255 green:SHKFormBgColorGreen/255 blue:SHKFormBgColorBlue/255 alpha:1]; +} + + +#pragma mark - +#pragma mark Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return sections.count; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [[[sections objectAtIndex:section] objectForKey:@"rows"] count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + + SHKCustomFormFieldCell *cell = (SHKCustomFormFieldCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) + { + cell = [[[SHKCustomFormFieldCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; + cell.form = self; + + if (SHKFormFontColorRed != -1) + cell.textLabel.textColor = [UIColor colorWithRed:SHKFormFontColorRed/255 green:SHKFormFontColorGreen/255 blue:SHKFormFontColorBlue/255 alpha:1]; + } + + // Since we are reusing table cells, make sure to save any existing values before overwriting + if (cell.settings.key != nil && [cell getValue]) + [values setObject:[cell getValue] forKey:cell.settings.key]; + + cell.settings = [self rowSettingsForIndexPath:indexPath]; + cell.labelWidth = labelWidth; + cell.textLabel.text = cell.settings.label; + + NSString *value = [values objectForKey:cell.settings.key]; + if (value == nil && cell.settings.start != nil) + value = cell.settings.start; + + [cell setValue:value]; + + return cell; +} + +- (SHKFormFieldSettings *)rowSettingsForIndexPath:(NSIndexPath *)indexPath +{ + return [[[sections objectAtIndex:indexPath.section] objectForKey:@"rows"] objectAtIndex:indexPath.row]; +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section +{ + return [[sections objectAtIndex:section] objectForKey:@"header"]; +} + +- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section +{ + return [[sections objectAtIndex:section] objectForKey:@"footer"]; +} + + +#pragma mark - + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + + +#pragma mark - +#pragma mark UITextFieldDelegate + +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + [self validateForm]; + return YES; +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField +{ + self.activeField = textField; +} + + +#pragma mark - +#pragma mark Completion + +- (void)close +{ + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; +} + +- (void)cancel +{ + [self close]; +} + +- (void)validateForm +{ + [activeField resignFirstResponder]; + [delegate performSelector:validateSelector withObject:self]; +} + +- (void)saveForm +{ + [delegate performSelector:saveSelector withObject:self]; + [self close]; +} + +#pragma mark - + +- (NSMutableDictionary *)formValues +{ + return [self formValuesForSection:0]; +} + +- (NSMutableDictionary *)formValuesForSection:(int)section +{ + // go through all form fields and get values + NSMutableDictionary *formValues = [NSMutableDictionary dictionaryWithCapacity:0]; + + SHKCustomFormFieldCell *cell; + int row = 0; + NSArray *fields = [[sections objectAtIndex:section] objectForKey:@"rows"]; + + for(SHKFormFieldSettings *field in fields) + { + cell = (SHKCustomFormFieldCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]]; + + // Use text field if visible first + if ([cell.settings.key isEqualToString:field.key] && [cell getValue] != nil) + [formValues setObject:[cell getValue] forKey:field.key]; + + // If field is not visible, use cached value + else if ([values objectForKey:field.key] != nil) + [formValues setObject:[values objectForKey:field.key] forKey:field.key]; + + row++; + } + + return formValues; +} + + + + +@end + diff --git a/Classes/ShareKit/UI/SHKFormFieldCell.h b/Classes/ShareKit/UI/SHKFormFieldCell.h new file mode 100644 index 00000000..4f86115c --- /dev/null +++ b/Classes/ShareKit/UI/SHKFormFieldCell.h @@ -0,0 +1,61 @@ +// +// SHKFormFieldCell.h +// ShareKit +// +// Created by Nathan Weiner on 6/17/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHK.h" + +@class SHKFormController; + +@interface SHKFormFieldCell : UITableViewCell +{ + SHKFormFieldSettings *settings; + + CGFloat labelWidth; + + UITextField *textField; + UISwitch *toggle; + + NSString *tmpValue; + + SHKFormController *form; +} + +@property (retain) SHKFormFieldSettings *settings; + +@property (nonatomic) CGFloat labelWidth; + +@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain) UISwitch *toggle; + +@property (nonatomic, retain) NSString *tmpValue; + +@property (nonatomic, assign) SHKFormController *form; + +- (void)setValue:(NSString *)value; +- (NSString *)getValue; + +@end diff --git a/Classes/ShareKit/UI/SHKFormFieldCell.m b/Classes/ShareKit/UI/SHKFormFieldCell.m new file mode 100644 index 00000000..f4b330ed --- /dev/null +++ b/Classes/ShareKit/UI/SHKFormFieldCell.m @@ -0,0 +1,156 @@ +// +// SHKFormFieldCell.m +// ShareKit +// +// Created by Nathan Weiner on 6/17/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKFormFieldCell.h" +#import "SHKCustomFormController.h" + +@implementation SHKFormFieldCell + +@synthesize settings; +@synthesize labelWidth; +@synthesize textField, toggle, tmpValue; +@synthesize form; + +#define SHK_FORM_CELL_PAD_LEFT 24 +#define SHK_FORM_CELL_PAD_RIGHT 10 + + +- (void)dealloc +{ + [settings release]; + [textField release]; + [toggle release]; + [tmpValue release]; + [super dealloc]; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + if (settings.type == SHKFormFieldTypeText || settings.type == SHKFormFieldTypePassword) + { + if (textField == nil) + { + self.textField = [[UITextField alloc] initWithFrame:CGRectMake(0,0,0,25)]; + textField.clearsOnBeginEditing = NO; + textField.returnKeyType = UIReturnKeyDone; + textField.font = [UIFont systemFontOfSize:17]; + textField.textColor = [UIColor darkGrayColor]; + textField.autocapitalizationType = UITextAutocapitalizationTypeNone; + textField.delegate = form; + [self.contentView addSubview:textField]; + [textField release]; + + [self setValue:tmpValue]; + } + + textField.secureTextEntry = settings.type == SHKFormFieldTypePassword; + + textField.frame = CGRectMake(labelWidth + SHK_FORM_CELL_PAD_LEFT, + 2 + round(self.contentView.bounds.size.height/2 - textField.bounds.size.height/2), + self.contentView.bounds.size.width - SHK_FORM_CELL_PAD_RIGHT - SHK_FORM_CELL_PAD_LEFT - labelWidth, + textField.bounds.size.height); + + if (toggle != nil) + [toggle removeFromSuperview]; + } + + else if (settings.type == SHKFormFieldTypeSwitch) + { + if (toggle == nil) + { + self.toggle = [[UISwitch alloc] initWithFrame:CGRectZero]; + [self.contentView addSubview:toggle]; + [self setValue:tmpValue]; + [toggle release]; + } + + toggle.frame = CGRectMake(self.contentView.bounds.size.width-toggle.bounds.size.width-SHK_FORM_CELL_PAD_RIGHT, + round(self.contentView.bounds.size.height/2-toggle.bounds.size.height/2), + toggle.bounds.size.width, + toggle.bounds.size.height); + + if (textField != nil) + [textField removeFromSuperview]; + } + + [self.contentView bringSubviewToFront:textField]; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + // don't actually select the row + //[super setSelected:selected animated:animated]; + + if (selected) + [textField becomeFirstResponder]; + + else + [textField resignFirstResponder]; +} + + +#pragma mark - + +- (void)setSettings:(SHKFormFieldSettings *)s +{ + [settings release]; + settings = [s retain]; + [self setNeedsLayout]; +} + +- (void)setValue:(NSString *)value +{ + self.tmpValue = value; // used to hold onto the value in case the form field element is created after this is set + + switch (settings.type) + { + case SHKFormFieldTypeSwitch: + [toggle setOn:[value isEqualToString:SHKFormFieldSwitchOn] animated:NO]; + break; + + case SHKFormFieldTypeText: + case SHKFormFieldTypePassword: + textField.text = value; + break; + } +} + +- (NSString *)getValue +{ + switch (settings.type) + { + case SHKFormFieldTypeSwitch: + return toggle.on ? SHKFormFieldSwitchOn : SHKFormFieldSwitchOff; + break; + } + + return textField.text; +} + +@end diff --git a/Classes/ShareKit/UI/SHKFormFieldSettings.h b/Classes/ShareKit/UI/SHKFormFieldSettings.h new file mode 100644 index 00000000..4db9aba8 --- /dev/null +++ b/Classes/ShareKit/UI/SHKFormFieldSettings.h @@ -0,0 +1,55 @@ +// +// SHKFormFieldSettings.h +// ShareKit +// +// Created by Nathan Weiner on 6/22/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + +typedef enum +{ + SHKFormFieldTypeText, + SHKFormFieldTypePassword, + SHKFormFieldTypeSwitch +} SHKFormFieldType; + +#define SHKFormFieldSwitchOff @"0" +#define SHKFormFieldSwitchOn @"1" + +@interface SHKFormFieldSettings : NSObject +{ + NSString *label; + NSString *key; + SHKFormFieldType type; + NSString *start; +} + +@property (nonatomic, retain) NSString *label; +@property (nonatomic, retain) NSString *key; +@property SHKFormFieldType type; +@property (nonatomic, retain) NSString *start; + ++ (id)label:(NSString *)l key:(NSString *)k type:(SHKFormFieldType)t start:(NSString *)s; + +@end diff --git a/Classes/ShareKit/UI/SHKFormFieldSettings.m b/Classes/ShareKit/UI/SHKFormFieldSettings.m new file mode 100644 index 00000000..c58826fb --- /dev/null +++ b/Classes/ShareKit/UI/SHKFormFieldSettings.m @@ -0,0 +1,54 @@ +// +// SHKFormFieldSettings.m +// ShareKit +// +// Created by Nathan Weiner on 6/22/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKFormFieldSettings.h" + + +@implementation SHKFormFieldSettings + +@synthesize label, key, type, start; + +- (void)dealloc +{ + [label release]; + [key release]; + [start release]; + + [super dealloc]; +} + ++ (id)label:(NSString *)l key:(NSString *)k type:(SHKFormFieldType)t start:(NSString *)s +{ + SHKFormFieldSettings *settings = [[SHKFormFieldSettings alloc] init]; + settings.label = l; + settings.key = k; + settings.type = t; + settings.start = s; + return [settings autorelease]; +} + +@end diff --git a/Classes/ShareKit/UI/SHKNavController.h b/Classes/ShareKit/UI/SHKNavController.h new file mode 100644 index 00000000..4413e6bd --- /dev/null +++ b/Classes/ShareKit/UI/SHKNavController.h @@ -0,0 +1,36 @@ +// +// SHKNavController.h +// ShareKit +// +// Created by Nathan Weiner on 6/28/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface SHKNavController : UINavigationController +{ + +} + +@end diff --git a/Classes/ShareKit/UI/SHKNavController.m b/Classes/ShareKit/UI/SHKNavController.m new file mode 100644 index 00000000..69ece22d --- /dev/null +++ b/Classes/ShareKit/UI/SHKNavController.m @@ -0,0 +1,38 @@ + // +// SHKNavController.m +// ShareKit +// +// Created by Nathan Weiner on 6/28/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKNavController.h" + + +@implementation SHKNavController + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + +@end diff --git a/Classes/ShareKit/UI/SHKOAuthView.h b/Classes/ShareKit/UI/SHKOAuthView.h new file mode 100644 index 00000000..ed9160a8 --- /dev/null +++ b/Classes/ShareKit/UI/SHKOAuthView.h @@ -0,0 +1,57 @@ +// +// SHKTwitterAuthView.h +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + +@class SHKOAuthView; +@class SHKOAuthSharer; + +@protocol SHKOAuthViewDelegate + +- (void)tokenAuthorizeView:(SHKOAuthView *)authView didFinishWithSuccess:(BOOL)success queryParams:(NSMutableDictionary *)queryParams error:(NSError *)error; +- (NSURL *)authorizeCallbackURL; + +@end + + +@interface SHKOAuthView : UIViewController +{ + UIWebView *webView; + id delegate; + UIActivityIndicatorView *spinner; +} + +@property (nonatomic, retain) UIWebView *webView; +@property (retain) id delegate; +@property (nonatomic, retain) UIActivityIndicatorView *spinner; + +- (id)initWithURL:(NSURL *)authorizeURL delegate:(id)d; + +- (void)startSpinner; +- (void)stopSpinner; + +@end diff --git a/Classes/ShareKit/UI/SHKOAuthView.m b/Classes/ShareKit/UI/SHKOAuthView.m new file mode 100644 index 00000000..1b1e252c --- /dev/null +++ b/Classes/ShareKit/UI/SHKOAuthView.m @@ -0,0 +1,158 @@ + // +// SHKTwitterAuthView.m +// ShareKit +// +// Created by Nathan Weiner on 6/21/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKOAuthView.h" +#import "SHK.h" +#import "SHKOAuthSharer.h" + +@implementation SHKOAuthView + +@synthesize webView, delegate, spinner; + +- (void)dealloc +{ + [webView release]; + [delegate release]; + [spinner release]; + [super dealloc]; +} + +- (id)initWithURL:(NSURL *)authorizeURL delegate:(id)d +{ + if ((self = [super initWithNibName:nil bundle:nil])) + { + [self.navigationItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(cancel)] autorelease] animated:NO]; + + self.delegate = d; + + self.webView = [[UIWebView alloc] initWithFrame:CGRectZero]; + webView.delegate = self; + webView.scalesPageToFit = YES; + [webView release]; + + [webView loadRequest:[NSURLRequest requestWithURL:authorizeURL]]; + + } + return self; +} + +- (void)loadView +{ + self.view = webView; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + // Remove the SHK view wrapper from the window + [[SHK currentHelper] viewWasDismissed]; +} + + +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType +{ + if ([request.URL.absoluteString rangeOfString:[delegate authorizeCallbackURL].absoluteString].location != NSNotFound) + { + // Get query + NSMutableDictionary *queryParams = nil; + if (request.URL.query != nil) + { + queryParams = [NSMutableDictionary dictionaryWithCapacity:0]; + NSArray *vars = [request.URL.query componentsSeparatedByString:@"&"]; + NSArray *parts; + for(NSString *var in vars) + { + parts = [var componentsSeparatedByString:@"="]; + if (parts.count == 2) + [queryParams setObject:[parts objectAtIndex:1] forKey:[parts objectAtIndex:0]]; + } + } + + [delegate tokenAuthorizeView:self didFinishWithSuccess:YES queryParams:queryParams error:nil]; + self.delegate = nil; + + return NO; + } + + return YES; +} + +- (void)webViewDidStartLoad:(UIWebView *)webView +{ + [self startSpinner]; +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView +{ + [self stopSpinner]; +} + +- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error +{ + if ([error code] != NSURLErrorCancelled && [error code] != 102 && [error code] != NSURLErrorFileDoesNotExist) + { + [self stopSpinner]; + [delegate tokenAuthorizeView:self didFinishWithSuccess:NO queryParams:nil error:error]; + } +} + +- (void)startSpinner +{ + if (spinner == nil) + { + self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; + [self.navigationItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithCustomView:spinner] autorelease] animated:NO]; + spinner.hidesWhenStopped = YES; + [spinner release]; + } + + [spinner startAnimating]; +} + +- (void)stopSpinner +{ + [spinner stopAnimating]; +} + + +#pragma mark - + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + +- (void)cancel +{ + [delegate tokenAuthorizeView:self didFinishWithSuccess:NO queryParams:nil error:[SHK error:@"User cancelled login"]]; + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; +} + +@end diff --git a/Classes/ShareKit/UI/SHKShareMenu.h b/Classes/ShareKit/UI/SHKShareMenu.h new file mode 100644 index 00000000..36193be7 --- /dev/null +++ b/Classes/ShareKit/UI/SHKShareMenu.h @@ -0,0 +1,56 @@ +// +// SHKShareMenu.h +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHK.h" + +@interface SHKShareMenu : UITableViewController +{ + SHKItem *item; + NSMutableArray *tableData; + NSMutableDictionary *exclusions; +} + +@property (retain) SHKItem *item; +@property (retain) NSMutableArray *tableData; +@property (retain) NSMutableDictionary *exclusions; + + +- (void)rebuildTableDataAnimated:(BOOL)animated; +- (NSMutableArray *)section:(NSString *)section; +- (NSDictionary *)rowDataAtIndexPath:(NSIndexPath *)indexPath; + +#pragma mark - +#pragma mark Toolbar Buttons + +- (void)cancel; +- (void)edit; +- (void)save; + + + +@end diff --git a/Classes/ShareKit/UI/SHKShareMenu.m b/Classes/ShareKit/UI/SHKShareMenu.m new file mode 100644 index 00000000..20f806ca --- /dev/null +++ b/Classes/ShareKit/UI/SHKShareMenu.m @@ -0,0 +1,325 @@ +// +// SHKShareMenu.m +// ShareKit +// +// Created by Nathan Weiner on 6/18/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKShareMenu.h" +#import "SHK.h" +#import "SHKSharer.h" +#import "SHKCustomShareMenuCell.h" + +@implementation SHKShareMenu + +@synthesize item; +@synthesize tableData; +@synthesize exclusions; + +#pragma mark - +#pragma mark Initialization + +- (void)dealloc +{ + [item release]; + [tableData release]; + [exclusions release]; + [super dealloc]; +} + + +- (id)initWithStyle:(UITableViewStyle)style +{ + if (self = [super initWithStyle:style]) + { + self.title = @"Share"; + + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(cancel)]; + + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Edit" + style:UIBarButtonItemStyleBordered + target:self + action:@selector(edit)]; + + } + return self; +} + +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + // Remove the SHK view wrapper from the window + [[SHK currentHelper] viewWasDismissed]; +} + + +- (void)setItem:(SHKItem *)i +{ + [item release]; + item = [i retain]; + + [self rebuildTableDataAnimated:NO]; +} + +- (void)rebuildTableDataAnimated:(BOOL)animated +{ + self.tableView.allowsSelectionDuringEditing = YES; + self.tableData = [NSMutableArray arrayWithCapacity:0]; + [tableData addObject:[self section:@"actions"]]; + [tableData addObject:[self section:@"services"]]; + + // Handling Excluded items + // If in editing mode, show them + // If not editing, hide them + self.exclusions = [[[[NSUserDefaults standardUserDefaults] objectForKey:@"SHKExcluded"] mutableCopy] autorelease]; + + if (exclusions == nil) + self.exclusions = [NSMutableDictionary dictionaryWithCapacity:0]; + + NSMutableArray *excluded = [NSMutableArray arrayWithCapacity:0]; + + if (!self.tableView.editing || animated) + { + int s = 0; + int r = 0; + + // Use temp objects so we can mutate as we are enumerating + NSMutableArray *sectionCopy; + NSMutableDictionary *tableDataCopy = [[tableData mutableCopy] autorelease]; + NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc] init]; + + for(NSMutableArray *section in tableDataCopy) + { + r = 0; + [indexes removeAllIndexes]; + + sectionCopy = [[section mutableCopy] autorelease]; + + for (NSMutableDictionary *row in section) + { + if ([exclusions objectForKey:[row objectForKey:@"className"]]) + { + [excluded addObject:[NSIndexPath indexPathForRow:r inSection:s]]; + + if (!self.tableView.editing) + [indexes addIndex:r]; + } + + r++; + } + + if (!self.tableView.editing) + { + [sectionCopy removeObjectsAtIndexes:indexes]; + [tableData replaceObjectAtIndex:s withObject:sectionCopy]; + } + + s++; + } + + [indexes release]; + + if (animated) + { + [self.tableView beginUpdates]; + + if (!self.tableView.editing) + [self.tableView deleteRowsAtIndexPaths:excluded withRowAnimation:UITableViewRowAnimationFade]; + else + [self.tableView insertRowsAtIndexPaths:excluded withRowAnimation:UITableViewRowAnimationFade]; + + [self.tableView endUpdates]; + } + } + +} + +- (NSMutableArray *)section:(NSString *)section +{ + id class; + NSMutableArray *sectionData = [NSMutableArray arrayWithCapacity:0]; + NSArray *source = [[SHK sharersDictionary] objectForKey:section];; + + for( NSString *sharerClassName in source) + { + class = NSClassFromString(sharerClassName); + if ( [class canShare] && [class canShareType:item.shareType] ) + [sectionData addObject:[NSDictionary dictionaryWithObjectsAndKeys:sharerClassName,@"className",[class sharerTitle],@"name",nil]]; + } + + if (sectionData.count) + [sectionData sortUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease]]]; + + return sectionData; +} + +#pragma mark - +#pragma mark View lifecycle + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + + +#pragma mark - +#pragma mark Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return tableData.count; +} + + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [[tableData objectAtIndex:section] count]; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + + SHKCustomShareMenuCell *cell = (SHKCustomShareMenuCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) + { + cell = [[[SHKCustomShareMenuCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + } + + NSDictionary *rowData = [self rowDataAtIndexPath:indexPath]; + cell.textLabel.text = [rowData objectForKey:@"name"]; + + if (cell.editingAccessoryView == nil) + { + UISwitch *toggle = [[UISwitch alloc] initWithFrame:CGRectZero]; + toggle.userInteractionEnabled = NO; + cell.editingAccessoryView = toggle; + [toggle release]; + } + + [(UISwitch *)cell.editingAccessoryView setOn:[exclusions objectForKey:[rowData objectForKey:@"className"]] == nil]; + + return cell; +} + +- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return UITableViewCellEditingStyleNone; +} + +- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath +{ + return NO; +} + + +#pragma mark - +#pragma mark Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSDictionary *rowData = [self rowDataAtIndexPath:indexPath]; + + if (tableView.editing) + { + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + + UISwitch *toggle = (UISwitch *)[cell editingAccessoryView]; + [toggle setOn:!toggle.on animated:YES]; + + if (toggle.on) + [exclusions removeObjectForKey:[rowData objectForKey:@"className"]]; + + else + [exclusions setObject:@"1" forKey:[rowData objectForKey:@"className"]]; + + [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; + } + + else + { + [objc_getClass([[rowData objectForKey:@"className"] UTF8String]) shareItem:item]; // TODO - make this warning go away + + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; + } +} + +- (NSDictionary *)rowDataAtIndexPath:(NSIndexPath *)indexPath +{ + return [[tableData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]; +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section +{ + if ([[tableData objectAtIndex:section] count]) + { + if (section == 0) + return @"Actions"; + + else if (section == 1) + return @"Services"; + } + + return nil; +} + + +#pragma mark - +#pragma mark Toolbar Buttons + +- (void)cancel +{ + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; +} + +- (void)edit +{ + [self.tableView setEditing:YES animated:YES]; + [self rebuildTableDataAnimated:YES]; + + [self.navigationItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone + target:self + action:@selector(save)] autorelease] animated:YES]; +} + +- (void)save +{ + [[NSUserDefaults standardUserDefaults] setObject:exclusions forKey:@"SHKExcluded"]; + + [self.tableView setEditing:NO animated:YES]; + [self rebuildTableDataAnimated:YES]; + + [self.navigationItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Edit" + style:UIBarButtonItemStyleBordered + target:self + action:@selector(edit)] autorelease] animated:YES]; + +} + +@end + diff --git a/Classes/ShareKit/UI/SHKViewControllerWrapper.h b/Classes/ShareKit/UI/SHKViewControllerWrapper.h new file mode 100644 index 00000000..c672216a --- /dev/null +++ b/Classes/ShareKit/UI/SHKViewControllerWrapper.h @@ -0,0 +1,35 @@ +// +// SHKViewControllerWrapper.h +// ShareKit +// +// Created by Nathan Weiner on 6/28/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import + + +@interface SHKViewControllerWrapper : UIViewController { + +} + +@end diff --git a/Classes/ShareKit/UI/SHKViewControllerWrapper.m b/Classes/ShareKit/UI/SHKViewControllerWrapper.m new file mode 100644 index 00000000..5da50bce --- /dev/null +++ b/Classes/ShareKit/UI/SHKViewControllerWrapper.m @@ -0,0 +1,38 @@ + // +// SHKViewControllerWrapper.m +// ShareKit +// +// Created by Nathan Weiner on 6/28/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKViewControllerWrapper.h" + + +@implementation SHKViewControllerWrapper + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + +@end diff --git a/MainWindow.xib b/MainWindow.xib new file mode 100644 index 00000000..0cac026c --- /dev/null +++ b/MainWindow.xib @@ -0,0 +1,279 @@ + + + + 800 + 10D541 + 760 + 1038.29 + 460.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 81 + + + YES + + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + YES + + + YES + + + + YES + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + IBCocoaTouchFramework + + + + 1316 + + {320, 480} + + 1 + MSAxIDEAA + + NO + NO + + IBCocoaTouchFramework + YES + + + + IBCocoaTouchFramework + + + 256 + {0, 0} + NO + YES + YES + IBCocoaTouchFramework + + + YES + + + + IBCocoaTouchFramework + + + RootViewController + + IBCocoaTouchFramework + + + + + + + YES + + + delegate + + + + 4 + + + + window + + + + 5 + + + + navigationController + + + + 15 + + + + + YES + + 0 + + + + + + 2 + + + YES + + + + + -1 + + + File's Owner + + + 3 + + + + + -2 + + + + + 9 + + + YES + + + + + + + 11 + + + + + 13 + + + YES + + + + + + 14 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 11.IBPluginDependency + 13.CustomClassName + 13.IBPluginDependency + 2.IBAttributePlaceholdersKey + 2.IBEditorWindowLastContentRect + 2.IBPluginDependency + 3.CustomClassName + 3.IBPluginDependency + 9.IBEditorWindowLastContentRect + 9.IBPluginDependency + + + YES + UIApplication + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + RootViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + YES + + + YES + + + {{673, 376}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + ShareKitAppDelegate + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + {{186, 376}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + YES + + + + + YES + + + YES + + + + 15 + + + + YES + + RootViewController + UITableViewController + + IBProjectSource + Classes/RootViewController.h + + + + ShareKitAppDelegate + NSObject + + YES + + YES + navigationController + window + + + YES + UINavigationController + UIWindow + + + + IBProjectSource + Classes/ShareKitAppDelegate.h + + + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + ShareKit.xcodeproj + 3 + 81 + + diff --git a/RootViewController.xib b/RootViewController.xib new file mode 100644 index 00000000..de9ed051 --- /dev/null +++ b/RootViewController.xib @@ -0,0 +1,384 @@ + + + + 784 + 10D541 + 760 + 1038.29 + 460.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 81 + + + YES + + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + YES + + + YES + + + + YES + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + {320, 247} + + + 3 + MQA + + NO + YES + NO + IBCocoaTouchFramework + NO + 1 + 0 + YES + 44 + 22 + 22 + + + + + YES + + + view + + + + 3 + + + + dataSource + + + + 4 + + + + delegate + + + + 5 + + + + + YES + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 2 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 2.IBEditorWindowLastContentRect + 2.IBPluginDependency + + + YES + RootViewController + UIResponder + {{144, 609}, {320, 247}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + YES + + + + + YES + + + YES + + + + 5 + + + + YES + + RootViewController + UITableViewController + + IBProjectSource + Classes/RootViewController.h + + + + + YES + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSNetServices.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPort.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSStream.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSXMLParser.h + + + + NSObject + + IBFrameworkSource + UIKit.framework/Headers/UIAccessibility.h + + + + NSObject + + IBFrameworkSource + UIKit.framework/Headers/UINibLoading.h + + + + NSObject + + IBFrameworkSource + UIKit.framework/Headers/UIResponder.h + + + + UIResponder + NSObject + + + + UIScrollView + UIView + + IBFrameworkSource + UIKit.framework/Headers/UIScrollView.h + + + + UISearchBar + UIView + + IBFrameworkSource + UIKit.framework/Headers/UISearchBar.h + + + + UISearchDisplayController + NSObject + + IBFrameworkSource + UIKit.framework/Headers/UISearchDisplayController.h + + + + UITableView + UIScrollView + + IBFrameworkSource + UIKit.framework/Headers/UITableView.h + + + + UITableViewController + UIViewController + + IBFrameworkSource + UIKit.framework/Headers/UITableViewController.h + + + + UIView + + IBFrameworkSource + UIKit.framework/Headers/UITextField.h + + + + UIView + UIResponder + + IBFrameworkSource + UIKit.framework/Headers/UIView.h + + + + UIViewController + + IBFrameworkSource + UIKit.framework/Headers/UINavigationController.h + + + + UIViewController + + IBFrameworkSource + UIKit.framework/Headers/UITabBarController.h + + + + UIViewController + UIResponder + + IBFrameworkSource + UIKit.framework/Headers/UIViewController.h + + + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + ShareKit.xcodeproj + 3 + 81 + + diff --git a/ShareKit-Info.plist b/ShareKit-Info.plist new file mode 100644 index 00000000..32894445 --- /dev/null +++ b/ShareKit-Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + NSMainNibFile + MainWindow + + diff --git a/ShareKit.xcodeproj/nate.mode1v3 b/ShareKit.xcodeproj/nate.mode1v3 new file mode 100644 index 00000000..140dff64 --- /dev/null +++ b/ShareKit.xcodeproj/nate.mode1v3 @@ -0,0 +1,1469 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1v3 + FavBarConfig + + PBXProjectModuleGUID + 4362EB7611B9A14600E3DB3A + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1v3 + MajorVersion + 33 + MinorVersion + 0 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-combo-popup + action + NSToolbarFlexibleSpaceItem + debugger-enable-breakpoints + go + buildOrClean + build-and-go + com.apple.ide.PBXToolbarStopButton + NSToolbarFlexibleSpaceItem + servicesModuledebug + com.apple.ide.organizer + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 316 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 080E96DDFE201D6D7F000001 + 43A5367111DBE3B9004A1712 + 43A536AD11DBE3B9004A1712 + 43A5367211DBE3B9004A1712 + 43A5367311DBE3B9004A1712 + 43A5367B11DBE3B9004A1712 + 43A536B511DBE3B9004A1712 + 43A536B611DBE3B9004A1712 + 43A536B711DBE3B9004A1712 + 43A536C011DBE3B9004A1712 + 43A536C411DBE3B9004A1712 + 43A536DE11DBE3B9004A1712 + 43A536E411DBE3B9004A1712 + 43A536E711DBE3B9004A1712 + 43A536ED11DBE3B9004A1712 + 4362EB3311B9937300E3DB3A + 29B97315FDCFA39411CA2CEA + 29B97317FDCFA39411CA2CEA + 29B97323FDCFA39411CA2CEA + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 45 + 43 + 33 + 26 + 2 + 1 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 208}, {316, 813}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {333, 831}} + GroupTreeTableConfiguration + + MainColumn + 316 + + RubberWindowFrame + 14 124 1183 872 0 0 1280 1002 + + Module + PBXSmartGroupTreeModule + Proportion + 333pt + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + SHKReadItLater.m + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + SHKReadItLater.m + _historyCapacity + 0 + bookmark + 439B96B711E2985F00ABE3BF + history + + 4362EB6D11B9A14600E3DB3A + 43EF404B11D3FC5100B1F700 + 43EF404D11D3FC5100B1F700 + 43EF404F11D3FC5100B1F700 + 43EF405111D3FC5100B1F700 + 43EF406211D3FF0200B1F700 + 43C7D65111D93C3E00E59A6F + 43A532B211DBD7B5004A1712 + 43A532B311DBD7B5004A1712 + 43A532B511DBD7B5004A1712 + 43A5381D11DBE42D004A1712 + 43A53C6711DC0AF8004A1712 + 43A53C6811DC0AF8004A1712 + 43A53C6911DC0AF8004A1712 + 43A53C6C11DC0AF8004A1712 + 43A53C6D11DC0AF8004A1712 + 43A53C6F11DC0AF8004A1712 + 43A53D1D11DD221F004A1712 + 43A53D1E11DD221F004A1712 + 43A53D1F11DD221F004A1712 + 43A53D2011DD221F004A1712 + 43A53D2111DD221F004A1712 + 43A53D2E11DD221F004A1712 + 43A53D8C11DD5018004A1712 + 43A53D8D11DD5018004A1712 + 43B665DD11DD544700BDBA80 + 43B665F711DD572D00BDBA80 + 43B665F811DD572D00BDBA80 + 43B665F911DD572D00BDBA80 + 43B665FA11DD572D00BDBA80 + 43B665FB11DD572D00BDBA80 + 43B6662611DD57D600BDBA80 + 43B6662D11DD586F00BDBA80 + 43B6663111DD591600BDBA80 + 43B6667111DE4AB700BDBA80 + 43C3FBA511DE844F002FA9FD + 43C3FBA611DE844F002FA9FD + 43C3FBA711DE844F002FA9FD + 439B966011E289A200ABE3BF + 439B966611E2909300ABE3BF + 439B967B11E2926900ABE3BF + 439B967C11E2926900ABE3BF + 439B969E11E295CC00ABE3BF + 439B969F11E295CC00ABE3BF + 439B96A011E295CC00ABE3BF + 439B96A111E295CC00ABE3BF + 439B96A711E2981100ABE3BF + 439B96B611E2985F00ABE3BF + 439B96B311E2984300ABE3BF + + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {845, 826}} + RubberWindowFrame + 14 124 1183 872 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 826pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 831}, {845, 0}} + RubberWindowFrame + 14 124 1183 872 0 0 1280 1002 + + Module + XCDetailModule + Proportion + 0pt + + + Proportion + 845pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + 439B964011E288A300ABE3BF + 1CE0B1FE06471DED0097A5F4 + 439B964111E288A300ABE3BF + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + 0 + Layout + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 337}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 1 + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 355}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 373 269 690 397 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 100% + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + 11E0B1FE06471DED0097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default.shortV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? + WindowJustification + 5 + WindowOrderList + + 439B96B011E2983100ABE3BF + 439B964D11E288A300ABE3BF + 439B964E11E288A300ABE3BF + 1CD10A99069EF8BA00B06720 + 4362EB7711B9A14600E3DB3A + 1C530D57069F1CE1000CFCEE + 1C78EAAD065D492600B07095 + /Users/nate/Documents/Development/ShareKit/Working Copy/ShareKit.xcodeproj + + WindowString + 14 124 1183 872 0 0 1280 1002 + WindowToolsV3 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + SHKTwitterForm.m + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {953, 445}} + RubberWindowFrame + -1136 159 953 825 -1280 0 1280 1024 + + Module + PBXNavigatorGroup + Proportion + 445pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build Results + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 450}, {953, 334}} + RubberWindowFrame + -1136 159 953 825 -1280 0 1280 1024 + + Module + PBXBuildResultsModule + Proportion + 334pt + + + Proportion + 784pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + 4362EB7711B9A14600E3DB3A + 439B964211E288A300ABE3BF + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowContentMinSize + 486 300 + WindowString + -1136 159 953 825 -1280 0 1280 1024 + WindowToolGUID + 4362EB7711B9A14600E3DB3A + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {470, 338}} + {{470, 0}, {373, 338}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {843, 338}} + {{0, 338}, {843, 295}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {843, 633}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 120 + Value + 85 + Summary + 143 + + Frame + {{470, 0}, {373, 338}} + RubberWindowFrame + -1280 264 843 674 -1280 0 1280 1024 + + RubberWindowFrame + -1280 264 843 674 -1280 0 1280 1024 + + Module + PBXDebugSessionModule + Proportion + 633pt + + + Proportion + 633pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + 439B964311E288A300ABE3BF + 1C162984064C10D400B95A72 + 439B964411E288A300ABE3BF + 439B964511E288A300ABE3BF + 439B964611E288A300ABE3BF + 439B964711E288A300ABE3BF + 439B964811E288A300ABE3BF + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + -1280 264 843 674 -1280 0 1280 1024 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.find + IsVertical + + Layout + + + Dock + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + SHKSharer.m + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {981, 468}} + RubberWindowFrame + -1246 94 981 890 -1280 0 1280 1024 + + Module + PBXNavigatorGroup + Proportion + 981pt + + + Proportion + 468pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{0, 473}, {981, 376}} + RubberWindowFrame + -1246 94 981 890 -1280 0 1280 1024 + + Module + PBXProjectFindModule + Proportion + 376pt + + + Proportion + 849pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + + TableOfContents + + 1C530D57069F1CE1000CFCEE + 439B964911E288A300ABE3BF + 439B964A11E288A300ABE3BF + 1CDD528C0622207200134675 + 1CD0528E0623707200166675 + + WindowString + -1246 94 981 890 -1280 0 1280 1024 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {728, 717}} + RubberWindowFrame + -1247 241 728 758 -1280 0 1280 1024 + + Module + PBXDebugCLIModule + Proportion + 717pt + + + Proportion + 717pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C78EAAD065D492600B07095 + 439B964B11E288A300ABE3BF + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + -1247 241 728 758 -1280 0 1280 1024 + WindowToolGUID + 1C78EAAD065D492600B07095 + WindowToolIsVisible + + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + Identifier + windowTool.scm + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1C78EAB3065D492600B07095 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM + + GeometryConfiguration + + ConsoleFrame + {{0, 259}, {452, 0}} + Frame + {{0, 7}, {452, 259}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + TableConfiguration + + Status + 30 + FileName + 199 + Path + 197.0950012207031 + + TableFrame + {{0, 0}, {452, 250}} + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 266pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAB4065D492600B07095 + 1C78EAB5065D492600B07095 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scm + WindowString + 743 379 452 308 0 0 1280 1002 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.breakpoints + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 42 515 744 409 0 0 1280 1002 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 42 515 744 409 0 0 1280 1002 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + + TableOfContents + + 4312CED111CB296200E61D7A + 4312CED211CB296200E61D7A + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + WindowString + 42 515 744 409 0 0 1280 1002 + WindowToolGUID + 4312CED111CB296200E61D7A + WindowToolIsVisible + + + + Identifier + windowTool.debugAnimator + Layout + + + Dock + + + Module + PBXNavigatorGroup + Proportion + 100% + + + Proportion + 100% + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + 1 + ToolbarConfiguration + xcode.toolbar.config.debugAnimatorV3 + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 100% + + + Proportion + 100% + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.classBrowser + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {378, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {630, 332}} + MembersFrame + {{0, 101}, {378, 231}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 101 + PBXMemberBookColumnIdentifier + 22 + + RubberWindowFrame + 21 563 630 352 0 0 1280 1002 + + Module + PBXClassBrowserModule + Proportion + 332pt + + + Proportion + 332pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + + TableOfContents + + 1C0AD2AF069F1E9B00FABCE6 + 4374055411CFEB16005704D2 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 21 563 630 352 0 0 1280 1002 + WindowToolGUID + 1C0AD2AF069F1E9B00FABCE6 + WindowToolIsVisible + + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/ShareKit.xcodeproj/nate.pbxuser b/ShareKit.xcodeproj/nate.pbxuser new file mode 100644 index 00000000..b0478856 --- /dev/null +++ b/ShareKit.xcodeproj/nate.pbxuser @@ -0,0 +1,1472 @@ +// !$*UTF8*$! +{ + 1D6058900D05DD3D006BFB54 /* ShareKit */ = { + activeExec = 0; + executables = ( + 4362EB2811B9936600E3DB3A /* ShareKit */, + ); + }; + 28A0AAE50D9B0CCF005BE974 /* ShareKit_Prefix.pch */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1011, 865}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 322}"; + }; + }; + 29B97313FDCFA39411CA2CEA /* Project object */ = { + activeBuildConfigurationName = Debug; + activeExecutable = 4362EB2811B9936600E3DB3A /* ShareKit */; + activeSDKPreference = iphonesimulator4.0; + activeTarget = 1D6058900D05DD3D006BFB54 /* ShareKit */; + addToTargets = ( + 1D6058900D05DD3D006BFB54 /* ShareKit */, + ); + breakpoints = ( + 439B96B111E2984200ABE3BF /* SHKSharer.m:417 */, + ); + codeSenseManager = 4362EB3511B9937300E3DB3A /* Code sense */; + executables = ( + 4362EB2811B9936600E3DB3A /* ShareKit */, + ); + perUserDictionary = { + "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 20, + 198, + 20, + 99, + 99, + 29, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBreakpointsDataSource_ActionID, + PBXBreakpointsDataSource_TypeID, + PBXBreakpointsDataSource_BreakpointID, + PBXBreakpointsDataSource_UseID, + PBXBreakpointsDataSource_LocationID, + PBXBreakpointsDataSource_ConditionID, + PBXBreakpointsDataSource_IgnoreCountID, + PBXBreakpointsDataSource_ContinueID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 606, + 20, + 48, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFindDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFindDataSource_LocationID; + PBXFileTableDataSourceColumnWidthsKey = ( + 200, + 716, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFindDataSource_MessageID, + PBXFindDataSource_LocationID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 300055808; + PBXWorkspaceStateSaveDate = 300055808; + }; + perUserProjectItems = { + 4362EB6D11B9A14600E3DB3A = 4362EB6D11B9A14600E3DB3A /* PBXTextBookmark */; + 439B963B11E288A300ABE3BF /* PBXTextBookmark */ = 439B963B11E288A300ABE3BF /* PBXTextBookmark */; + 439B963C11E288A300ABE3BF /* PBXTextBookmark */ = 439B963C11E288A300ABE3BF /* PBXTextBookmark */; + 439B963D11E288A300ABE3BF /* PBXTextBookmark */ = 439B963D11E288A300ABE3BF /* PBXTextBookmark */; + 439B963E11E288A300ABE3BF /* PBXTextBookmark */ = 439B963E11E288A300ABE3BF /* PBXTextBookmark */; + 439B963F11E288A300ABE3BF /* PBXTextBookmark */ = 439B963F11E288A300ABE3BF /* PBXTextBookmark */; + 439B965511E2892800ABE3BF /* PBXTextBookmark */ = 439B965511E2892800ABE3BF /* PBXTextBookmark */; + 439B965611E2892800ABE3BF /* PBXTextBookmark */ = 439B965611E2892800ABE3BF /* PBXTextBookmark */; + 439B965711E2892800ABE3BF /* PBXTextBookmark */ = 439B965711E2892800ABE3BF /* PBXTextBookmark */; + 439B965D11E289A000ABE3BF /* PBXTextBookmark */ = 439B965D11E289A000ABE3BF /* PBXTextBookmark */; + 439B965E11E289A000ABE3BF /* PBXTextBookmark */ = 439B965E11E289A000ABE3BF /* PBXTextBookmark */; + 439B965F11E289A000ABE3BF /* PBXTextBookmark */ = 439B965F11E289A000ABE3BF /* PBXTextBookmark */; + 439B966011E289A200ABE3BF /* PBXTextBookmark */ = 439B966011E289A200ABE3BF /* PBXTextBookmark */; + 439B966111E289A200ABE3BF /* PBXTextBookmark */ = 439B966111E289A200ABE3BF /* PBXTextBookmark */; + 439B966211E289A200ABE3BF /* PBXTextBookmark */ = 439B966211E289A200ABE3BF /* PBXTextBookmark */; + 439B966611E2909300ABE3BF /* PBXTextBookmark */ = 439B966611E2909300ABE3BF /* PBXTextBookmark */; + 439B966711E2909300ABE3BF /* PBXTextBookmark */ = 439B966711E2909300ABE3BF /* PBXTextBookmark */; + 439B966811E2909300ABE3BF /* PBXTextBookmark */ = 439B966811E2909300ABE3BF /* PBXTextBookmark */; + 439B966911E2909300ABE3BF /* PBXTextBookmark */ = 439B966911E2909300ABE3BF /* PBXTextBookmark */; + 439B967B11E2926900ABE3BF /* PBXTextBookmark */ = 439B967B11E2926900ABE3BF /* PBXTextBookmark */; + 439B967C11E2926900ABE3BF /* PBXTextBookmark */ = 439B967C11E2926900ABE3BF /* PBXTextBookmark */; + 439B967D11E2926900ABE3BF /* PBXTextBookmark */ = 439B967D11E2926900ABE3BF /* PBXTextBookmark */; + 439B967E11E2926900ABE3BF /* PBXTextBookmark */ = 439B967E11E2926900ABE3BF /* PBXTextBookmark */; + 439B968211E292B400ABE3BF /* PBXTextBookmark */ = 439B968211E292B400ABE3BF /* PBXTextBookmark */; + 439B968411E292C700ABE3BF /* PBXTextBookmark */ = 439B968411E292C700ABE3BF /* PBXTextBookmark */; + 439B969411E2938F00ABE3BF /* PBXTextBookmark */ = 439B969411E2938F00ABE3BF /* PBXTextBookmark */; + 439B969911E293C500ABE3BF /* PBXTextBookmark */ = 439B969911E293C500ABE3BF /* PBXTextBookmark */; + 439B969E11E295CC00ABE3BF /* PBXTextBookmark */ = 439B969E11E295CC00ABE3BF /* PBXTextBookmark */; + 439B969F11E295CC00ABE3BF /* PBXTextBookmark */ = 439B969F11E295CC00ABE3BF /* PBXTextBookmark */; + 439B96A011E295CC00ABE3BF /* PBXTextBookmark */ = 439B96A011E295CC00ABE3BF /* PBXTextBookmark */; + 439B96A111E295CC00ABE3BF /* PBXTextBookmark */ = 439B96A111E295CC00ABE3BF /* PBXTextBookmark */; + 439B96A211E295CC00ABE3BF /* PBXTextBookmark */ = 439B96A211E295CC00ABE3BF /* PBXTextBookmark */; + 439B96A711E2981100ABE3BF /* PBXTextBookmark */ = 439B96A711E2981100ABE3BF /* PBXTextBookmark */; + 439B96A911E2981100ABE3BF /* PBXTextBookmark */ = 439B96A911E2981100ABE3BF /* PBXTextBookmark */; + 439B96AA11E2981100ABE3BF /* PBXTextBookmark */ = 439B96AA11E2981100ABE3BF /* PBXTextBookmark */; + 439B96AB11E2981100ABE3BF /* PBXTextBookmark */ = 439B96AB11E2981100ABE3BF /* PBXTextBookmark */; + 439B96AF11E2983100ABE3BF /* PBXTextBookmark */ = 439B96AF11E2983100ABE3BF /* PBXTextBookmark */; + 439B96B311E2984300ABE3BF /* PBXTextBookmark */ = 439B96B311E2984300ABE3BF /* PBXTextBookmark */; + 439B96B411E2984300ABE3BF /* PBXTextBookmark */ = 439B96B411E2984300ABE3BF /* PBXTextBookmark */; + 439B96B511E2984300ABE3BF /* PBXTextBookmark */ = 439B96B511E2984300ABE3BF /* PBXTextBookmark */; + 439B96B611E2985F00ABE3BF /* PBXTextBookmark */ = 439B96B611E2985F00ABE3BF /* PBXTextBookmark */; + 439B96B711E2985F00ABE3BF /* PBXTextBookmark */ = 439B96B711E2985F00ABE3BF /* PBXTextBookmark */; + 43A532B211DBD7B5004A1712 = 43A532B211DBD7B5004A1712 /* PBXTextBookmark */; + 43A532B311DBD7B5004A1712 = 43A532B311DBD7B5004A1712 /* PBXTextBookmark */; + 43A532B511DBD7B5004A1712 = 43A532B511DBD7B5004A1712 /* PBXTextBookmark */; + 43A5381D11DBE42D004A1712 = 43A5381D11DBE42D004A1712 /* PBXTextBookmark */; + 43A53C6711DC0AF8004A1712 = 43A53C6711DC0AF8004A1712 /* PBXTextBookmark */; + 43A53C6811DC0AF8004A1712 = 43A53C6811DC0AF8004A1712 /* PBXTextBookmark */; + 43A53C6911DC0AF8004A1712 = 43A53C6911DC0AF8004A1712 /* PBXTextBookmark */; + 43A53C6C11DC0AF8004A1712 = 43A53C6C11DC0AF8004A1712 /* PBXTextBookmark */; + 43A53C6D11DC0AF8004A1712 = 43A53C6D11DC0AF8004A1712 /* PBXTextBookmark */; + 43A53C6F11DC0AF8004A1712 = 43A53C6F11DC0AF8004A1712 /* PBXTextBookmark */; + 43A53D1D11DD221F004A1712 = 43A53D1D11DD221F004A1712 /* PBXTextBookmark */; + 43A53D1E11DD221F004A1712 = 43A53D1E11DD221F004A1712 /* PBXTextBookmark */; + 43A53D1F11DD221F004A1712 = 43A53D1F11DD221F004A1712 /* PBXTextBookmark */; + 43A53D2011DD221F004A1712 = 43A53D2011DD221F004A1712 /* PBXTextBookmark */; + 43A53D2111DD221F004A1712 = 43A53D2111DD221F004A1712 /* PBXTextBookmark */; + 43A53D2511DD221F004A1712 = 43A53D2511DD221F004A1712 /* PBXTextBookmark */; + 43A53D2711DD221F004A1712 = 43A53D2711DD221F004A1712 /* PBXTextBookmark */; + 43A53D2E11DD221F004A1712 = 43A53D2E11DD221F004A1712 /* PBXTextBookmark */; + 43A53D8C11DD5018004A1712 = 43A53D8C11DD5018004A1712 /* PBXTextBookmark */; + 43A53D8D11DD5018004A1712 = 43A53D8D11DD5018004A1712 /* PBXTextBookmark */; + 43B665DD11DD544700BDBA80 = 43B665DD11DD544700BDBA80 /* PBXTextBookmark */; + 43B665DE11DD544700BDBA80 = 43B665DE11DD544700BDBA80 /* PBXTextBookmark */; + 43B665F711DD572D00BDBA80 = 43B665F711DD572D00BDBA80 /* PBXTextBookmark */; + 43B665F811DD572D00BDBA80 = 43B665F811DD572D00BDBA80 /* PBXTextBookmark */; + 43B665F911DD572D00BDBA80 = 43B665F911DD572D00BDBA80 /* PBXTextBookmark */; + 43B665FA11DD572D00BDBA80 = 43B665FA11DD572D00BDBA80 /* PBXTextBookmark */; + 43B665FB11DD572D00BDBA80 = 43B665FB11DD572D00BDBA80 /* PBXTextBookmark */; + 43B6660D11DD575600BDBA80 = 43B6660D11DD575600BDBA80 /* PBXTextBookmark */; + 43B6661511DD57AF00BDBA80 = 43B6661511DD57AF00BDBA80 /* PBXTextBookmark */; + 43B6662611DD57D600BDBA80 = 43B6662611DD57D600BDBA80 /* PlistBookmark */; + 43B6662D11DD586F00BDBA80 = 43B6662D11DD586F00BDBA80 /* PBXTextBookmark */; + 43B6663111DD591600BDBA80 = 43B6663111DD591600BDBA80 /* PBXTextBookmark */; + 43B6667111DE4AB700BDBA80 = 43B6667111DE4AB700BDBA80 /* PBXTextBookmark */; + 43C3FBA511DE844F002FA9FD = 43C3FBA511DE844F002FA9FD /* PBXTextBookmark */; + 43C3FBA611DE844F002FA9FD = 43C3FBA611DE844F002FA9FD /* PBXTextBookmark */; + 43C3FBA711DE844F002FA9FD = 43C3FBA711DE844F002FA9FD /* PBXTextBookmark */; + 43C3FBA811DE844F002FA9FD = 43C3FBA811DE844F002FA9FD /* PBXTextBookmark */; + 43C3FBA911DE844F002FA9FD = 43C3FBA911DE844F002FA9FD /* PBXTextBookmark */; + 43C7D65111D93C3E00E59A6F = 43C7D65111D93C3E00E59A6F /* PBXTextBookmark */; + 43EF404B11D3FC5100B1F700 = 43EF404B11D3FC5100B1F700 /* PBXTextBookmark */; + 43EF404D11D3FC5100B1F700 = 43EF404D11D3FC5100B1F700 /* PBXTextBookmark */; + 43EF404F11D3FC5100B1F700 = 43EF404F11D3FC5100B1F700 /* PBXTextBookmark */; + 43EF405111D3FC5100B1F700 = 43EF405111D3FC5100B1F700 /* PBXTextBookmark */; + 43EF406211D3FF0200B1F700 = 43EF406211D3FF0200B1F700 /* PBXTextBookmark */; + }; + sourceControlManager = 4362EB3411B9937300E3DB3A /* Source Control */; + userBuildSettings = { + }; + }; + 4362EB2811B9936600E3DB3A /* ShareKit */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 1; + configStateDict = { + }; + customDataFormattersEnabled = 1; + dataTipCustomDataFormattersEnabled = 1; + dataTipShowTypeColumn = 1; + dataTipSortType = 0; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = ShareKit; + savedGlobals = { + }; + showTypeColumn = 0; + sourceDirectories = ( + ); + variableFormatDictionary = { + }; + }; + 4362EB3411B9937300E3DB3A /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + repositoryNamesForRoots = { + "" = ""; + }; + }; + }; + 4362EB3511B9937300E3DB3A /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + 4362EB6D11B9A14600E3DB3A /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 28A0AAE50D9B0CCF005BE974 /* ShareKit_Prefix.pch */; + name = "ShareKit_Prefix.pch: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 322; + vrLoc = 0; + }; + 438D425B11C1A294001F8560 /* SHK.h */ = { + isa = PBXFileReference; + fileEncoding = 4; + lastKnownFileType = sourcecode.c.h; + name = SHK.h; + path = "/Users/nate/Documents/Development/ShareKit/Working Copy/Classes/ShareKit/Core/SHK.h"; + sourceTree = ""; + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 1573}}"; + sepNavSelRange = "{3326, 0}"; + sepNavVisRange = "{1958, 1369}"; + }; + }; + 439B963B11E288A300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; + name = "SHKTwitter.m: 96"; + rLen = 0; + rLoc = 2786; + rType = 0; + vrLen = 898; + vrLoc = 2312; + }; + 439B963C11E288A300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 645"; + rLen = 0; + rLoc = 15511; + rType = 0; + vrLen = 1609; + vrLoc = 14151; + }; + 439B963D11E288A300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367611DBE3B9004A1712 /* SHKSharer.h */; + name = "SHKSharer.h: 104"; + rLen = 0; + rLoc = 2735; + rType = 0; + vrLen = 1203; + vrLoc = 2033; + }; + 439B963E11E288A300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; + rLen = 23; + rLoc = 2176; + rType = 0; + }; + 439B963F11E288A300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; + name = "SHKFacebook.m: 100"; + rLen = 23; + rLoc = 2176; + rType = 0; + vrLen = 1224; + vrLoc = 3653; + }; + 439B965511E2892800ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 277"; + rLen = 0; + rLoc = 5810; + rType = 0; + vrLen = 1520; + vrLoc = 4770; + }; + 439B965611E2892800ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; + rLen = 0; + rLoc = 189; + rType = 1; + }; + 439B965711E2892800ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; + name = "SHKFacebook.m: 189"; + rLen = 0; + rLoc = 4404; + rType = 0; + vrLen = 1318; + vrLoc = 3552; + }; + 439B965D11E289A000ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; + name = "SHKFacebook.m: 187"; + rLen = 23; + rLoc = 4330; + rType = 0; + vrLen = 569; + vrLoc = 3945; + }; + 439B965E11E289A000ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; + name = "SHKFacebook.m: 187"; + rLen = 23; + rLoc = 4330; + rType = 0; + vrLen = 568; + vrLoc = 3945; + }; + 439B965F11E289A000ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; + name = "SHKFacebook.m: 187"; + rLen = 23; + rLoc = 4330; + rType = 0; + vrLen = 568; + vrLoc = 3945; + }; + 439B966011E289A200ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; + name = "SHKFacebook.m: 186"; + rLen = 0; + rLoc = 4305; + rType = 0; + vrLen = 1318; + vrLoc = 3552; + }; + 439B966111E289A200ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; + name = "SHKTwitter.m: 96"; + rLen = 0; + rLoc = 2786; + rType = 0; + vrLen = 858; + vrLoc = 2312; + }; + 439B966211E289A200ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; + name = "SHKTwitter.m: 151"; + rLen = 0; + rLoc = 3992; + rType = 0; + vrLen = 1883; + vrLoc = 3039; + }; + 439B966611E2909300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; + name = "SHKTwitter.m: 151"; + rLen = 0; + rLoc = 3992; + rType = 0; + vrLen = 1883; + vrLoc = 3039; + }; + 439B966711E2909300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; + name = "SHKActivityIndicator.m: 150"; + rLen = 16; + rLoc = 4406; + rType = 0; + vrLen = 1058; + vrLoc = 3162; + }; + 439B966811E2909300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; + name = "SHKCopy.m: 83"; + rLen = 0; + rLoc = 1923; + rType = 0; + vrLen = 770; + vrLoc = 1171; + }; + 439B966911E2909300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; + name = "SHKCopy.m: 83"; + rLen = 0; + rLoc = 1948; + rType = 0; + vrLen = 795; + vrLoc = 1171; + }; + 439B967B11E2926900ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; + name = "SHKCopy.m: 83"; + rLen = 0; + rLoc = 1948; + rType = 0; + vrLen = 795; + vrLoc = 1171; + }; + 439B967C11E2926900ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 438D425B11C1A294001F8560 /* SHK.h */; + name = "SHK.h: 120"; + rLen = 0; + rLoc = 3326; + rType = 0; + vrLen = 1369; + vrLoc = 1958; + }; + 439B967D11E2926900ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; + name = "SHKActivityIndicator.m: 255"; + rLen = 0; + rLoc = 7650; + rType = 0; + vrLen = 1862; + vrLoc = 5314; + }; + 439B967E11E2926900ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; + name = "SHKActivityIndicator.m: 251"; + rLen = 0; + rLoc = 7581; + rType = 0; + vrLen = 1934; + vrLoc = 5256; + }; + 439B968211E292B400ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; + name = "SHKActivityIndicator.m: 248"; + rLen = 0; + rLoc = 7149; + rType = 0; + vrLen = 1754; + vrLoc = 5604; + }; + 439B968411E292C700ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; + name = "SHKActivityIndicator.m: 242"; + rLen = 0; + rLoc = 7022; + rType = 0; + vrLen = 1737; + vrLoc = 5604; + }; + 439B969411E2938F00ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; + name = "SHKActivityIndicator.m: 83"; + rLen = 0; + rLoc = 2877; + rType = 0; + vrLen = 1828; + vrLoc = 1467; + }; + 439B969911E293C500ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; + name = "SHKActivityIndicator.m: 68"; + rLen = 0; + rLoc = 2548; + rType = 0; + vrLen = 1755; + vrLoc = 1412; + }; + 439B969E11E295CC00ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */; + name = "SHKTwitterForm.m: 128"; + rLen = 0; + rLoc = 3933; + rType = 0; + vrLen = 1885; + vrLoc = 3095; + }; + 439B969F11E295CC00ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; + name = "SHKActivityIndicator.m: 248"; + rLen = 102; + rLoc = 6918; + rType = 0; + vrLen = 1487; + vrLoc = 6247; + }; + 439B96A011E295CC00ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F011DBE3B9004A1712 /* SHKActivityIndicator.h */; + name = "SHKActivityIndicator.h: 24"; + rLen = 0; + rLoc = 1177; + rType = 0; + vrLen = 1920; + vrLoc = 0; + }; + 439B96A111E295CC00ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367611DBE3B9004A1712 /* SHKSharer.h */; + name = "SHKSharer.h: 104"; + rLen = 0; + rLoc = 2735; + rType = 0; + vrLen = 1155; + vrLoc = 2033; + }; + 439B96A211E295CC00ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 263"; + rLen = 0; + rLoc = 5428; + rType = 0; + vrLen = 1473; + vrLoc = 4817; + }; + 439B96A711E2981100ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 439B96A811E2981100ABE3BF /* New Web Service.m */; + name = "New Web Service.m: 221"; + rLen = 22; + rLoc = 6227; + rType = 0; + vrLen = 1466; + vrLoc = 6003; + }; + 439B96A811E2981100ABE3BF /* New Web Service.m */ = { + isa = PBXFileReference; + name = "New Web Service.m"; + path = "/Users/nate/Documents/Development/ShareKit/Working Copy/Template Src/ShareKit/New Web Service.m"; + sourceTree = ""; + }; + 439B96A911E2981100ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 508"; + rLen = 0; + rLoc = 12068; + rType = 0; + vrLen = 1702; + vrLoc = 10798; + }; + 439B96AA11E2981100ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; + name = "SHKReadItLater.m: 135"; + rLen = 12; + rLoc = 3580; + rType = 0; + vrLen = 1499; + vrLoc = 2065; + }; + 439B96AB11E2981100ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; + name = "SHKReadItLater.m: 120"; + rLen = 0; + rLoc = 3213; + rType = 0; + vrLen = 1387; + vrLoc = 2384; + }; + 439B96AF11E2983100ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; + name = "SHKReadItLater.m: 56"; + rLen = 0; + rLoc = 1712; + rType = 0; + vrLen = 1439; + vrLoc = 627; + }; + 439B96B111E2984200ABE3BF /* SHKSharer.m:417 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + functionName = "-show"; + hitCount = 1; + ignoreCount = 0; + lineNumber = 417; + location = ShareKit; + modificationTime = 300062788.685467; + originalNumberOfMultipleMatches = 1; + state = 1; + }; + 439B96B311E2984300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; + name = "SHKReadItLater.m: 56"; + rLen = 0; + rLoc = 1712; + rType = 0; + vrLen = 1439; + vrLoc = 627; + }; + 439B96B411E2984300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 508"; + rLen = 0; + rLoc = 12068; + rType = 0; + vrLen = 1552; + vrLoc = 8931; + }; + 439B96B511E2984300ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 508"; + rLen = 0; + rLoc = 12068; + rType = 0; + vrLen = 1554; + vrLoc = 8929; + }; + 439B96B611E2985F00ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 508"; + rLen = 0; + rLoc = 12068; + rType = 0; + vrLen = 1238; + vrLoc = 12353; + }; + 439B96B711E2985F00ABE3BF /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; + name = "SHKReadItLater.m: 119"; + rLen = 0; + rLoc = 3213; + rType = 0; + vrLen = 1654; + vrLoc = 2694; + }; + 43A532B211DBD7B5004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43C7E12A11DBC47E00E59A6F /* class.m */; + name = "class.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 223; + vrLoc = 0; + }; + 43A532B311DBD7B5004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A532B411DBD7B5004A1712 /* New Action.h */; + name = "New Action.h: 15"; + rLen = 0; + rLoc = 252; + rType = 0; + vrLen = 259; + vrLoc = 0; + }; + 43A532B411DBD7B5004A1712 /* New Action.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "New Action.h"; + path = "/Users/nate/Library/Application Support/Developer/Shared/Xcode/File Templates/ShareKit/New Action.h"; + sourceTree = ""; + }; + 43A532B511DBD7B5004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A532B611DBD7B5004A1712 /* New Web Service.h */; + name = "New Web Service.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 259; + vrLoc = 0; + }; + 43A532B611DBD7B5004A1712 /* New Web Service.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "New Web Service.h"; + path = "/Users/nate/Library/Application Support/Developer/Shared/Xcode/File Templates/ShareKit/New Web Service.h"; + sourceTree = ""; + }; + 43A532B811DBD7B5004A1712 /* New Web Service.m */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = "New Web Service.m"; + path = "/Users/nate/Library/Application Support/Developer/Shared/Xcode/File Templates/ShareKit/New Web Service.m"; + sourceTree = ""; + }; + 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1111, 3510}}"; + sepNavSelRange = "{6701, 0}"; + sepNavVisRange = "{6490, 1081}"; + sepNavWindowFrame = "{{67, 67}, {1047, 916}}"; + }; + }; + 43A5367611DBE3B9004A1712 /* SHKSharer.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {817, 2171}}"; + sepNavSelRange = "{2735, 0}"; + sepNavVisRange = "{2033, 1155}"; + }; + }; + 43A5367711DBE3B9004A1712 /* SHKSharer.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1300, 8021}}"; + sepNavSelRange = "{12068, 0}"; + sepNavVisRange = "{12353, 1238}"; + sepNavWindowFrame = "{{-1163, 72}, {1047, 916}}"; + }; + }; + 43A5367E11DBE3B9004A1712 /* SFHFKeychainUtils.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1055, 5486}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 2389}"; + }; + }; + 43A5368F11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1181, 1560}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 2200}"; + }; + }; + 43A5369611DBE3B9004A1712 /* OAMutableURLRequest.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 871}}"; + sepNavSelRange = "{149, 1086}"; + sepNavVisRange = "{0, 2228}"; + }; + }; + 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1622, 2964}}"; + sepNavSelRange = "{7349, 0}"; + sepNavVisRange = "{5669, 2469}"; + }; + }; + 43A536A511DBE3B9004A1712 /* SHKRequest.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {988, 1664}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{1282, 1470}"; + sepNavWindowFrame = "{{203, 59}, {1047, 916}}"; + }; + }; + 43A536A711DBE3B9004A1712 /* SHK.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1219, 6318}}"; + sepNavSelRange = "{5365, 0}"; + sepNavVisRange = "{5268, 1011}"; + }; + }; + 43A536A811DBE3B9004A1712 /* SHKItem.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {831, 884}}"; + sepNavSelRange = "{1373, 22}"; + sepNavVisRange = "{74, 1444}"; + }; + }; + 43A536AB11DBE3B9004A1712 /* SHKOfflineSharer.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1219, 1716}}"; + sepNavSelRange = "{2127, 10}"; + sepNavVisRange = "{1679, 886}"; + }; + }; + 43A536AE11DBE3B9004A1712 /* SHKCustomFormController.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1219, 469}}"; + sepNavSelRange = "{1183, 0}"; + sepNavVisRange = "{0, 1319}"; + }; + }; + 43A536AF11DBE3B9004A1712 /* SHKCustomFormController.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 1742}}"; + sepNavSelRange = "{1183, 0}"; + sepNavVisRange = "{3, 2123}"; + }; + }; + 43A536B011DBE3B9004A1712 /* SHKCustomFormFieldCell.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; + sepNavSelRange = "{273, 0}"; + sepNavVisRange = "{0, 280}"; + }; + }; + 43A536B111DBE3B9004A1712 /* SHKCustomFormFieldCell.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 746}}"; + sepNavSelRange = "{1353, 0}"; + sepNavVisRange = "{0, 1353}"; + }; + }; + 43A536B911DBE3B9004A1712 /* SHKCopy.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 1157}}"; + sepNavSelRange = "{1948, 0}"; + sepNavVisRange = "{1171, 795}"; + }; + }; + 43A536BC11DBE3B9004A1712 /* SHKMail.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1244, 2795}}"; + sepNavSelRange = "{3067, 25}"; + sepNavVisRange = "{2467, 1053}"; + }; + }; + 43A536C311DBE3B9004A1712 /* SHKDelicious.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1748, 2275}}"; + sepNavSelRange = "{4770, 0}"; + sepNavVisRange = "{4141, 642}"; + sepNavWindowFrame = "{{126, 86}, {1047, 916}}"; + }; + }; + 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {920, 2743}}"; + sepNavSelRange = "{4330, 23}"; + sepNavVisRange = "{3945, 568}"; + }; + }; + 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {978, 3900}}"; + sepNavSelRange = "{8194, 0}"; + sepNavVisRange = "{6873, 1486}"; + }; + }; + 43A536E311DBE3B9004A1712 /* SHKPinboard.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1279, 2015}}"; + sepNavSelRange = "{3614, 0}"; + sepNavVisRange = "{2847, 780}"; + }; + }; + 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {894, 2236}}"; + sepNavSelRange = "{3213, 0}"; + sepNavVisRange = "{2694, 1654}"; + sepNavWindowFrame = "{{145, 59}, {1047, 916}}"; + }; + }; + 43A536E911DBE3B9004A1712 /* SHKTwitter.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1734, 4940}}"; + sepNavSelRange = "{3992, 0}"; + sepNavVisRange = "{3039, 1883}"; + }; + }; + 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1174, 2574}}"; + sepNavSelRange = "{3933, 0}"; + sepNavVisRange = "{3543, 1023}"; + }; + }; + 43A536EC11DBE3B9004A1712 /* SHKConfig.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1734, 1586}}"; + sepNavSelRange = "{3443, 0}"; + sepNavVisRange = "{1347, 2640}"; + }; + }; + 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {929, 1079}}"; + sepNavSelRange = "{1097, 0}"; + sepNavVisRange = "{410, 1504}"; + }; + }; + 43A536F011DBE3B9004A1712 /* SHKActivityIndicator.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 780}}"; + sepNavSelRange = "{1177, 0}"; + sepNavVisRange = "{0, 1920}"; + }; + }; + 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1426, 3614}}"; + sepNavSelRange = "{6918, 102}"; + sepNavVisRange = "{6247, 1487}"; + }; + }; + 43A536F211DBE3B9004A1712 /* SHKFormController.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {988, 832}}"; + sepNavSelRange = "{237, 0}"; + sepNavVisRange = "{40, 1304}"; + sepNavWindowFrame = "{{-1196, 40}, {1047, 916}}"; + }; + }; + 43A536F811DBE3B9004A1712 /* SHKNavController.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 236}"; + }; + }; + 43A536FA11DBE3B9004A1712 /* SHKOAuthView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1111, 724}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 861}"; + }; + }; + 43A536FC11DBE3B9004A1712 /* SHKShareMenu.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 707}"; + }; + }; + 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {908, 4095}}"; + sepNavSelRange = "{235, 0}"; + sepNavVisRange = "{0, 530}"; + }; + }; + 43A5381D11DBE42D004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A532B811DBD7B5004A1712 /* New Web Service.m */; + name = "New Web Service.m: 16"; + rLen = 0; + rLoc = 225; + rType = 0; + vrLen = 225; + vrLoc = 0; + }; + 43A5382F11DBE493004A1712 /* ExampleShareLink.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1139, 1027}}"; + sepNavSelRange = "{2100, 0}"; + sepNavVisRange = "{1427, 1174}"; + }; + }; + 43A5383111DBE493004A1712 /* ExampleShareText.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1219, 1170}}"; + sepNavSelRange = "{86, 1093}"; + sepNavVisRange = "{0, 1372}"; + }; + }; + 43A53C0711DC07A9004A1712 /* SHKCustomShareMenuCell.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; + sepNavSelRange = "{417, 22}"; + sepNavVisRange = "{0, 554}"; + }; + }; + 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {892, 413}}"; + sepNavSelRange = "{171, 0}"; + sepNavVisRange = "{0, 306}"; + }; + }; + 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; + sepNavSelRange = "{338, 0}"; + sepNavVisRange = "{0, 345}"; + }; + }; + 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; + sepNavSelRange = "{211, 82}"; + sepNavVisRange = "{0, 301}"; + }; + }; + 43A53C6711DC0AF8004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F811DBE3B9004A1712 /* SHKNavController.h */; + name = "SHKNavController.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 236; + vrLoc = 0; + }; + 43A53C6811DC0AF8004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536FA11DBE3B9004A1712 /* SHKOAuthView.h */; + name = "SHKOAuthView.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 861; + vrLoc = 0; + }; + 43A53C6911DC0AF8004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536FC11DBE3B9004A1712 /* SHKShareMenu.h */; + name = "SHKShareMenu.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 707; + vrLoc = 0; + }; + 43A53C6C11DC0AF8004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A53C0711DC07A9004A1712 /* SHKCustomShareMenuCell.h */; + name = "SHKCustomShareMenuCell.h: 21"; + rLen = 22; + rLoc = 1453; + rType = 0; + vrLen = 554; + vrLoc = 0; + }; + 43A53C6D11DC0AF8004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */; + name = "SHKCustomShareMenuCell.m: 14"; + rLen = 82; + rLoc = 1253; + rType = 0; + vrLen = 306; + vrLoc = 0; + }; + 43A53C6F11DC0AF8004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */; + name = "SHKCustomShareMenu.m: 14"; + rLen = 82; + rLoc = 1247; + rType = 0; + vrLen = 301; + vrLoc = 0; + }; + 43A53D1D11DD221F004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */; + name = "SHKShareMenu.m: 191"; + rLen = 0; + rLoc = 5838; + rType = 0; + vrLen = 1748; + vrLoc = 3493; + }; + 43A53D1E11DD221F004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536F211DBE3B9004A1712 /* SHKFormController.h */; + name = "SHKFormController.h: 11"; + rLen = 0; + rLoc = 1273; + rType = 0; + vrLen = 1224; + vrLoc = 0; + }; + 43A53D1F11DD221F004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536B011DBE3B9004A1712 /* SHKCustomFormFieldCell.h */; + name = "SHKCustomFormFieldCell.h: 15"; + rLen = 0; + rLoc = 1309; + rType = 0; + vrLen = 280; + vrLoc = 0; + }; + 43A53D2011DD221F004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536AE11DBE3B9004A1712 /* SHKCustomFormController.h */; + name = "SHKCustomFormController.h: 12"; + rLen = 0; + rLoc = 1307; + rType = 0; + vrLen = 283; + vrLoc = 0; + }; + 43A53D2111DD221F004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */; + name = "SHKCustomShareMenu.h: 19"; + rLen = 0; + rLoc = 1374; + rType = 0; + vrLen = 345; + vrLoc = 0; + }; + 43A53D2511DD221F004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; + name = "SHKCopy.m: 13"; + rLen = 748; + rLoc = 1218; + rType = 0; + vrLen = 772; + vrLoc = 74; + }; + 43A53D2711DD221F004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; + name = "SHKReadItLater.m: 116"; + rLen = 12; + rLoc = 3580; + rType = 0; + vrLen = 1710; + vrLoc = 1849; + }; + 43A53D2E11DD221F004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536C311DBE3B9004A1712 /* SHKDelicious.m */; + name = "SHKDelicious.m: 55"; + rLen = 361; + rLoc = 2339; + rType = 0; + vrLen = 1443; + vrLoc = 608; + }; + 43A53D8C11DD5018004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5382F11DBE493004A1712 /* ExampleShareLink.m */; + name = "ExampleShareLink.m: 49"; + rLen = 0; + rLoc = 2469; + rType = 0; + vrLen = 1591; + vrLoc = 0; + }; + 43A53D8D11DD5018004A1712 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; + name = "SHKActionSheet.m: 50"; + rLen = 0; + rLoc = 2133; + rType = 0; + vrLen = 1504; + vrLoc = 410; + }; + 43B665DD11DD544700BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536A811DBE3B9004A1712 /* SHKItem.h */; + name = "SHKItem.h: 62"; + rLen = 22; + rLoc = 2409; + rType = 0; + vrLen = 1444; + vrLoc = 74; + }; + 43B665DE11DD544700BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367611DBE3B9004A1712 /* SHKSharer.h */; + name = "SHKSharer.h: 69"; + rLen = 0; + rLoc = 2504; + rType = 0; + vrLen = 1155; + vrLoc = 997; + }; + 43B665F711DD572D00BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367E11DBE3B9004A1712 /* SFHFKeychainUtils.m */; + name = "SFHFKeychainUtils.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 2389; + vrLoc = 0; + }; + 43B665F811DD572D00BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5368F11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m */; + name = "OAAsynchronousDataFetcher.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 2200; + vrLoc = 0; + }; + 43B665F911DD572D00BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5369611DBE3B9004A1712 /* OAMutableURLRequest.h */; + name = "OAMutableURLRequest.h: 8"; + rLen = 1086; + rLoc = 149; + rType = 0; + vrLen = 2228; + vrLoc = 0; + }; + 43B665FA11DD572D00BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536AF11DBE3B9004A1712 /* SHKCustomFormController.m */; + name = "SHKCustomFormController.m: 25"; + rLen = 0; + rLoc = 1183; + rType = 0; + vrLen = 2123; + vrLoc = 3; + }; + 43B665FB11DD572D00BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536B111DBE3B9004A1712 /* SHKCustomFormFieldCell.m */; + name = "SHKCustomFormFieldCell.m: 36"; + rLen = 0; + rLoc = 1353; + rType = 0; + vrLen = 1353; + vrLoc = 0; + }; + 43B6660D11DD575600BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 645"; + rLen = 0; + rLoc = 15511; + rType = 0; + vrLen = 1580; + vrLoc = 14180; + }; + 43B6661511DD57AF00BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 438D425B11C1A294001F8560 /* SHK.h */; + name = "SHK.h: 29"; + rLen = 0; + rLoc = 1197; + rType = 0; + vrLen = 1602; + vrLoc = 534; + }; + 43B6662611DD57D600BDBA80 /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 43A536AC11DBE3B9004A1712 /* SHKSharers.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + ); + name = "/Users/nate/Documents/Development/ShareKit/Working Copy/Classes/ShareKit/Core/SHKSharers.plist"; + rLen = 0; + rLoc = 9223372036854775808; + }; + 43B6662D11DD586F00BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536A711DBE3B9004A1712 /* SHK.m */; + name = "SHK.m: 209"; + rLen = 13; + rLoc = 5689; + rType = 0; + vrLen = 1427; + vrLoc = 5134; + }; + 43B6663111DD591600BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */; + name = "SHKGoogleReader.m: 293"; + rLen = 0; + rLoc = 8194; + rType = 0; + vrLen = 1486; + vrLoc = 6873; + }; + 43B6667111DE4AB700BDBA80 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536BC11DBE3B9004A1712 /* SHKMail.m */; + name = "SHKMail.m: 131"; + rLen = 4; + rLoc = 3130; + rType = 0; + vrLen = 1660; + vrLoc = 2451; + }; + 43C3FBA511DE844F002FA9FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EC11DBE3B9004A1712 /* SHKConfig.h */; + name = "SHKConfig.h: 51"; + rLen = 0; + rLoc = 1953; + rType = 0; + vrLen = 2728; + vrLoc = 1258; + }; + 43C3FBA611DE844F002FA9FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */; + name = "OAMutableURLRequest.m: 209"; + rLen = 0; + rLoc = 7349; + rType = 0; + vrLen = 2469; + vrLoc = 5669; + }; + 43C3FBA711DE844F002FA9FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; + name = "SHKOAuthSharer.m: 205"; + rLen = 0; + rLoc = 6701; + rType = 0; + vrLen = 1703; + vrLoc = 6557; + }; + 43C3FBA811DE844F002FA9FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; + name = "SHKTwitter.m: 149"; + rLen = 64; + rLoc = 3913; + rType = 0; + vrLen = 1881; + vrLoc = 3346; + }; + 43C3FBA911DE844F002FA9FD /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; + name = "SHKTwitter.m: 149"; + rLen = 64; + rLoc = 3913; + rType = 0; + vrLen = 898; + vrLoc = 2312; + }; + 43C7D65111D93C3E00E59A6F /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43C7D65211D93C3E00E59A6F /* OAMutableURLRequest.h */; + name = "OAMutableURLRequest.h: 55"; + rLen = 0; + rLoc = 2031; + rType = 0; + vrLen = 1129; + vrLoc = 1295; + }; + 43C7D65211D93C3E00E59A6F /* OAMutableURLRequest.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = OAMutableURLRequest.h; + path = "/Users/nate/Documents/tmp/oauth-read-only/OAMutableURLRequest.h"; + sourceTree = ""; + }; + 43C7E12A11DBC47E00E59A6F /* class.m */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = class.m; + path = "/Developer/Library/Xcode/File Templates/Cocoa Class/Objective-C class/Objective-C class.pbfiletemplate/class.m"; + sourceTree = ""; + }; + 43EF404B11D3FC5100B1F700 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43EF404C11D3FC5100B1F700 /* NSMutableURLRequest+Parameters.h */; + name = "NSMutableURLRequest+Parameters.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1609; + vrLoc = 0; + }; + 43EF404C11D3FC5100B1F700 /* NSMutableURLRequest+Parameters.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "NSMutableURLRequest+Parameters.h"; + path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/Categories/NSMutableURLRequest+Parameters.h"; + sourceTree = ""; + }; + 43EF404D11D3FC5100B1F700 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43EF404E11D3FC5100B1F700 /* NSString+URLEncoding.h */; + name = "NSString+URLEncoding.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1441; + vrLoc = 0; + }; + 43EF404E11D3FC5100B1F700 /* NSString+URLEncoding.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "NSString+URLEncoding.h"; + path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/Categories/NSString+URLEncoding.h"; + sourceTree = ""; + }; + 43EF404F11D3FC5100B1F700 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43EF405011D3FC5100B1F700 /* NSURL+Base.h */; + name = "NSURL+Base.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1344; + vrLoc = 0; + }; + 43EF405011D3FC5100B1F700 /* NSURL+Base.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = "NSURL+Base.h"; + path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/Categories/NSURL+Base.h"; + sourceTree = ""; + }; + 43EF405111D3FC5100B1F700 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43EF405211D3FC5100B1F700 /* OAToken_KeychainExtensions.h */; + name = "OAToken_KeychainExtensions.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 583; + vrLoc = 0; + }; + 43EF405211D3FC5100B1F700 /* OAToken_KeychainExtensions.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = OAToken_KeychainExtensions.h; + path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/OAToken_KeychainExtensions.h"; + sourceTree = ""; + }; + 43EF405411D3FC5100B1F700 /* OAToken_KeychainExtensions.m */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + name = OAToken_KeychainExtensions.m; + path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/OAToken_KeychainExtensions.m"; + sourceTree = ""; + }; + 43EF406211D3FF0200B1F700 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43EF405411D3FC5100B1F700 /* OAToken_KeychainExtensions.m */; + name = "OAToken_KeychainExtensions.m: 79"; + rLen = 29; + rLoc = 2662; + rType = 0; + vrLen = 1564; + vrLoc = 1852; + }; +} diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj new file mode 100755 index 00000000..14b4b2cb --- /dev/null +++ b/ShareKit.xcodeproj/project.pbxproj @@ -0,0 +1,892 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; + 2892E4100DC94CBA00A64D0F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */; }; + 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD735F0D9D9599002E5188 /* MainWindow.xib */; }; + 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28F335F01007B36200424DE2 /* RootViewController.xib */; }; + 4312CF7C11CB33E200E61D7A /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4312CF7B11CB33E200E61D7A /* MessageUI.framework */; }; + 43A5370011DBE3B9004A1712 /* SHKOAuthSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; }; + 43A5370111DBE3B9004A1712 /* SHKSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; }; + 43A5370211DBE3B9004A1712 /* UIWebView+SHK.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367A11DBE3B9004A1712 /* UIWebView+SHK.m */; }; + 43A5370311DBE3B9004A1712 /* SFHFKeychainUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367E11DBE3B9004A1712 /* SFHFKeychainUtils.m */; }; + 43A5370411DBE3B9004A1712 /* NSMutableURLRequest+Parameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5368211DBE3B9004A1712 /* NSMutableURLRequest+Parameters.m */; }; + 43A5370511DBE3B9004A1712 /* NSString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5368411DBE3B9004A1712 /* NSString+URLEncoding.m */; }; + 43A5370611DBE3B9004A1712 /* NSURL+Base.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5368611DBE3B9004A1712 /* NSURL+Base.m */; }; + 43A5370711DBE3B9004A1712 /* Base64Transcoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 43A5368811DBE3B9004A1712 /* Base64Transcoder.c */; }; + 43A5370811DBE3B9004A1712 /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 43A5368A11DBE3B9004A1712 /* hmac.c */; }; + 43A5370911DBE3B9004A1712 /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 43A5368C11DBE3B9004A1712 /* sha1.c */; }; + 43A5370A11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5368F11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m */; }; + 43A5370B11DBE3B9004A1712 /* OAConsumer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369111DBE3B9004A1712 /* OAConsumer.m */; }; + 43A5370C11DBE3B9004A1712 /* OADataFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369311DBE3B9004A1712 /* OADataFetcher.m */; }; + 43A5370D11DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369511DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.m */; }; + 43A5370E11DBE3B9004A1712 /* OAMutableURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */; }; + 43A5370F11DBE3B9004A1712 /* OAPlaintextSignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369911DBE3B9004A1712 /* OAPlaintextSignatureProvider.m */; }; + 43A5371011DBE3B9004A1712 /* OAProblem.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369B11DBE3B9004A1712 /* OAProblem.m */; }; + 43A5371111DBE3B9004A1712 /* OARequestParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369D11DBE3B9004A1712 /* OARequestParameter.m */; }; + 43A5371211DBE3B9004A1712 /* OAServiceTicket.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369F11DBE3B9004A1712 /* OAServiceTicket.m */; }; + 43A5371311DBE3B9004A1712 /* OAToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536A211DBE3B9004A1712 /* OAToken.m */; }; + 43A5371411DBE3B9004A1712 /* SHKRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536A511DBE3B9004A1712 /* SHKRequest.m */; }; + 43A5371511DBE3B9004A1712 /* SHK.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536A711DBE3B9004A1712 /* SHK.m */; }; + 43A5371611DBE3B9004A1712 /* SHKItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536A911DBE3B9004A1712 /* SHKItem.m */; }; + 43A5371711DBE3B9004A1712 /* SHKOfflineSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536AB11DBE3B9004A1712 /* SHKOfflineSharer.m */; }; + 43A5371811DBE3B9004A1712 /* SHKSharers.plist in Resources */ = {isa = PBXBuildFile; fileRef = 43A536AC11DBE3B9004A1712 /* SHKSharers.plist */; }; + 43A5371911DBE3B9004A1712 /* SHKCustomFormController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536AF11DBE3B9004A1712 /* SHKCustomFormController.m */; }; + 43A5371A11DBE3B9004A1712 /* SHKCustomFormFieldCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536B111DBE3B9004A1712 /* SHKCustomFormFieldCell.m */; }; + 43A5371B11DBE3B9004A1712 /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536B411DBE3B9004A1712 /* Reachability.m */; }; + 43A5371C11DBE3B9004A1712 /* SHKCopy.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; }; + 43A5371D11DBE3B9004A1712 /* SHKMail.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536BC11DBE3B9004A1712 /* SHKMail.m */; }; + 43A5371E11DBE3B9004A1712 /* SHKSafari.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536BF11DBE3B9004A1712 /* SHKSafari.m */; }; + 43A5371F11DBE3B9004A1712 /* SHKDelicious.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536C311DBE3B9004A1712 /* SHKDelicious.m */; }; + 43A5372011DBE3B9004A1712 /* FBConnect.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 43A536C611DBE3B9004A1712 /* FBConnect.bundle */; }; + 43A5372111DBE3B9004A1712 /* FBConnectGlobal.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */; }; + 43A5372211DBE3B9004A1712 /* FBDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CB11DBE3B9004A1712 /* FBDialog.m */; }; + 43A5372311DBE3B9004A1712 /* FBFeedDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */; }; + 43A5372411DBE3B9004A1712 /* FBLoginButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */; }; + 43A5372511DBE3B9004A1712 /* FBLoginDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */; }; + 43A5372611DBE3B9004A1712 /* FBPermissionDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */; }; + 43A5372711DBE3B9004A1712 /* FBRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D511DBE3B9004A1712 /* FBRequest.m */; }; + 43A5372811DBE3B9004A1712 /* FBSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D711DBE3B9004A1712 /* FBSession.m */; }; + 43A5372911DBE3B9004A1712 /* FBStreamDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */; }; + 43A5372A11DBE3B9004A1712 /* FBXMLHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */; }; + 43A5372B11DBE3B9004A1712 /* SHKFacebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; }; + 43A5372C11DBE3B9004A1712 /* SHKGoogleReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */; }; + 43A5372D11DBE3B9004A1712 /* SHKPinboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536E311DBE3B9004A1712 /* SHKPinboard.m */; }; + 43A5372E11DBE3B9004A1712 /* SHKReadItLater.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; }; + 43A5372F11DBE3B9004A1712 /* SHKTwitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; }; + 43A5373011DBE3B9004A1712 /* SHKTwitterForm.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */; }; + 43A5373111DBE3B9004A1712 /* SHKActionSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; }; + 43A5373211DBE3B9004A1712 /* SHKActivityIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; }; + 43A5373311DBE3B9004A1712 /* SHKFormController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F311DBE3B9004A1712 /* SHKFormController.m */; }; + 43A5373411DBE3B9004A1712 /* SHKFormFieldCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F511DBE3B9004A1712 /* SHKFormFieldCell.m */; }; + 43A5373511DBE3B9004A1712 /* SHKFormFieldSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F711DBE3B9004A1712 /* SHKFormFieldSettings.m */; }; + 43A5373611DBE3B9004A1712 /* SHKNavController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F911DBE3B9004A1712 /* SHKNavController.m */; }; + 43A5373711DBE3B9004A1712 /* SHKOAuthView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536FB11DBE3B9004A1712 /* SHKOAuthView.m */; }; + 43A5373811DBE3B9004A1712 /* SHKShareMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */; }; + 43A5373911DBE3B9004A1712 /* SHKViewControllerWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536FF11DBE3B9004A1712 /* SHKViewControllerWrapper.m */; }; + 43A5382811DBE480004A1712 /* example.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 43A5382611DBE480004A1712 /* example.pdf */; }; + 43A5382911DBE480004A1712 /* sanFran.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 43A5382711DBE480004A1712 /* sanFran.jpg */; }; + 43A5383611DBE493004A1712 /* ExampleShareFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5382B11DBE493004A1712 /* ExampleShareFile.m */; }; + 43A5383711DBE493004A1712 /* ExampleShareImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5382D11DBE493004A1712 /* ExampleShareImage.m */; }; + 43A5383811DBE493004A1712 /* ExampleShareLink.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5382F11DBE493004A1712 /* ExampleShareLink.m */; }; + 43A5383911DBE493004A1712 /* ExampleShareText.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5383111DBE493004A1712 /* ExampleShareText.m */; }; + 43A5383A11DBE493004A1712 /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5383311DBE493004A1712 /* RootViewController.m */; }; + 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */; }; + 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */; }; + 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */; }; + 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; + 43EF406E11D3FFF800B1F700 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43EF406D11D3FFF800B1F700 /* Security.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 1D6058910D05DD3D006BFB54 /* ShareKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShareKit.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 28A0AAE50D9B0CCF005BE974 /* ShareKit_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShareKit_Prefix.pch; sourceTree = ""; }; + 28AD735F0D9D9599002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; + 28F335F01007B36200424DE2 /* RootViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RootViewController.xib; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 4312CF7B11CB33E200E61D7A /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; + 43A5367411DBE3B9004A1712 /* SHKOAuthSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOAuthSharer.h; sourceTree = ""; }; + 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOAuthSharer.m; sourceTree = ""; }; + 43A5367611DBE3B9004A1712 /* SHKSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKSharer.h; sourceTree = ""; }; + 43A5367711DBE3B9004A1712 /* SHKSharer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKSharer.m; sourceTree = ""; }; + 43A5367911DBE3B9004A1712 /* UIWebView+SHK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIWebView+SHK.h"; sourceTree = ""; }; + 43A5367A11DBE3B9004A1712 /* UIWebView+SHK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIWebView+SHK.m"; sourceTree = ""; }; + 43A5367D11DBE3B9004A1712 /* SFHFKeychainUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFHFKeychainUtils.h; sourceTree = ""; }; + 43A5367E11DBE3B9004A1712 /* SFHFKeychainUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFHFKeychainUtils.m; sourceTree = ""; }; + 43A5368111DBE3B9004A1712 /* NSMutableURLRequest+Parameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableURLRequest+Parameters.h"; sourceTree = ""; }; + 43A5368211DBE3B9004A1712 /* NSMutableURLRequest+Parameters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableURLRequest+Parameters.m"; sourceTree = ""; }; + 43A5368311DBE3B9004A1712 /* NSString+URLEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+URLEncoding.h"; sourceTree = ""; }; + 43A5368411DBE3B9004A1712 /* NSString+URLEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+URLEncoding.m"; sourceTree = ""; }; + 43A5368511DBE3B9004A1712 /* NSURL+Base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+Base.h"; sourceTree = ""; }; + 43A5368611DBE3B9004A1712 /* NSURL+Base.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+Base.m"; sourceTree = ""; }; + 43A5368811DBE3B9004A1712 /* Base64Transcoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Base64Transcoder.c; sourceTree = ""; }; + 43A5368911DBE3B9004A1712 /* Base64Transcoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Base64Transcoder.h; sourceTree = ""; }; + 43A5368A11DBE3B9004A1712 /* hmac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hmac.c; sourceTree = ""; }; + 43A5368B11DBE3B9004A1712 /* hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hmac.h; sourceTree = ""; }; + 43A5368C11DBE3B9004A1712 /* sha1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sha1.c; sourceTree = ""; }; + 43A5368D11DBE3B9004A1712 /* sha1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha1.h; sourceTree = ""; }; + 43A5368E11DBE3B9004A1712 /* OAAsynchronousDataFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAAsynchronousDataFetcher.h; sourceTree = ""; }; + 43A5368F11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAAsynchronousDataFetcher.m; sourceTree = ""; }; + 43A5369011DBE3B9004A1712 /* OAConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAConsumer.h; sourceTree = ""; }; + 43A5369111DBE3B9004A1712 /* OAConsumer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAConsumer.m; sourceTree = ""; }; + 43A5369211DBE3B9004A1712 /* OADataFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OADataFetcher.h; sourceTree = ""; }; + 43A5369311DBE3B9004A1712 /* OADataFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OADataFetcher.m; sourceTree = ""; }; + 43A5369411DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAHMAC_SHA1SignatureProvider.h; sourceTree = ""; }; + 43A5369511DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAHMAC_SHA1SignatureProvider.m; sourceTree = ""; }; + 43A5369611DBE3B9004A1712 /* OAMutableURLRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAMutableURLRequest.h; sourceTree = ""; }; + 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAMutableURLRequest.m; sourceTree = ""; }; + 43A5369811DBE3B9004A1712 /* OAPlaintextSignatureProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAPlaintextSignatureProvider.h; sourceTree = ""; }; + 43A5369911DBE3B9004A1712 /* OAPlaintextSignatureProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAPlaintextSignatureProvider.m; sourceTree = ""; }; + 43A5369A11DBE3B9004A1712 /* OAProblem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAProblem.h; sourceTree = ""; }; + 43A5369B11DBE3B9004A1712 /* OAProblem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAProblem.m; sourceTree = ""; }; + 43A5369C11DBE3B9004A1712 /* OARequestParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OARequestParameter.h; sourceTree = ""; }; + 43A5369D11DBE3B9004A1712 /* OARequestParameter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OARequestParameter.m; sourceTree = ""; }; + 43A5369E11DBE3B9004A1712 /* OAServiceTicket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAServiceTicket.h; sourceTree = ""; }; + 43A5369F11DBE3B9004A1712 /* OAServiceTicket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAServiceTicket.m; sourceTree = ""; }; + 43A536A011DBE3B9004A1712 /* OASignatureProviding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OASignatureProviding.h; sourceTree = ""; }; + 43A536A111DBE3B9004A1712 /* OAToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAToken.h; sourceTree = ""; }; + 43A536A211DBE3B9004A1712 /* OAToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAToken.m; sourceTree = ""; }; + 43A536A311DBE3B9004A1712 /* OAuthConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAuthConsumer.h; sourceTree = ""; }; + 43A536A411DBE3B9004A1712 /* SHKRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKRequest.h; sourceTree = ""; }; + 43A536A511DBE3B9004A1712 /* SHKRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKRequest.m; sourceTree = ""; }; + 43A536A611DBE3B9004A1712 /* SHK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHK.h; sourceTree = ""; }; + 43A536A711DBE3B9004A1712 /* SHK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHK.m; sourceTree = ""; }; + 43A536A811DBE3B9004A1712 /* SHKItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKItem.h; sourceTree = ""; }; + 43A536A911DBE3B9004A1712 /* SHKItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKItem.m; sourceTree = ""; }; + 43A536AA11DBE3B9004A1712 /* SHKOfflineSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOfflineSharer.h; sourceTree = ""; }; + 43A536AB11DBE3B9004A1712 /* SHKOfflineSharer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOfflineSharer.m; sourceTree = ""; }; + 43A536AC11DBE3B9004A1712 /* SHKSharers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SHKSharers.plist; sourceTree = ""; }; + 43A536AE11DBE3B9004A1712 /* SHKCustomFormController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCustomFormController.h; sourceTree = ""; }; + 43A536AF11DBE3B9004A1712 /* SHKCustomFormController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomFormController.m; sourceTree = ""; }; + 43A536B011DBE3B9004A1712 /* SHKCustomFormFieldCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCustomFormFieldCell.h; sourceTree = ""; }; + 43A536B111DBE3B9004A1712 /* SHKCustomFormFieldCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomFormFieldCell.m; sourceTree = ""; }; + 43A536B311DBE3B9004A1712 /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = ""; }; + 43A536B411DBE3B9004A1712 /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = ""; }; + 43A536B811DBE3B9004A1712 /* SHKCopy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCopy.h; sourceTree = ""; }; + 43A536B911DBE3B9004A1712 /* SHKCopy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCopy.m; sourceTree = ""; }; + 43A536BB11DBE3B9004A1712 /* SHKMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKMail.h; sourceTree = ""; }; + 43A536BC11DBE3B9004A1712 /* SHKMail.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKMail.m; sourceTree = ""; }; + 43A536BE11DBE3B9004A1712 /* SHKSafari.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKSafari.h; sourceTree = ""; }; + 43A536BF11DBE3B9004A1712 /* SHKSafari.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKSafari.m; sourceTree = ""; }; + 43A536C211DBE3B9004A1712 /* SHKDelicious.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKDelicious.h; sourceTree = ""; }; + 43A536C311DBE3B9004A1712 /* SHKDelicious.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKDelicious.m; sourceTree = ""; }; + 43A536C611DBE3B9004A1712 /* FBConnect.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FBConnect.bundle; sourceTree = ""; }; + 43A536C711DBE3B9004A1712 /* FBConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnect.h; sourceTree = ""; }; + 43A536C811DBE3B9004A1712 /* FBConnectGlobal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnectGlobal.h; sourceTree = ""; }; + 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBConnectGlobal.m; sourceTree = ""; }; + 43A536CA11DBE3B9004A1712 /* FBDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBDialog.h; sourceTree = ""; }; + 43A536CB11DBE3B9004A1712 /* FBDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBDialog.m; sourceTree = ""; }; + 43A536CC11DBE3B9004A1712 /* FBFeedDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBFeedDialog.h; sourceTree = ""; }; + 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBFeedDialog.m; sourceTree = ""; }; + 43A536CE11DBE3B9004A1712 /* FBLoginButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginButton.h; sourceTree = ""; }; + 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginButton.m; sourceTree = ""; }; + 43A536D011DBE3B9004A1712 /* FBLoginDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginDialog.h; sourceTree = ""; }; + 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginDialog.m; sourceTree = ""; }; + 43A536D211DBE3B9004A1712 /* FBPermissionDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBPermissionDialog.h; sourceTree = ""; }; + 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBPermissionDialog.m; sourceTree = ""; }; + 43A536D411DBE3B9004A1712 /* FBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBRequest.h; sourceTree = ""; }; + 43A536D511DBE3B9004A1712 /* FBRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRequest.m; sourceTree = ""; }; + 43A536D611DBE3B9004A1712 /* FBSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSession.h; sourceTree = ""; }; + 43A536D711DBE3B9004A1712 /* FBSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSession.m; sourceTree = ""; }; + 43A536D811DBE3B9004A1712 /* FBStreamDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBStreamDialog.h; sourceTree = ""; }; + 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBStreamDialog.m; sourceTree = ""; }; + 43A536DA11DBE3B9004A1712 /* FBXMLHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBXMLHandler.h; sourceTree = ""; }; + 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBXMLHandler.m; sourceTree = ""; }; + 43A536DC11DBE3B9004A1712 /* SHKFacebook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFacebook.h; sourceTree = ""; }; + 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFacebook.m; sourceTree = ""; }; + 43A536DF11DBE3B9004A1712 /* SHKGoogleReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKGoogleReader.h; sourceTree = ""; }; + 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKGoogleReader.m; sourceTree = ""; }; + 43A536E211DBE3B9004A1712 /* SHKPinboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKPinboard.h; sourceTree = ""; }; + 43A536E311DBE3B9004A1712 /* SHKPinboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKPinboard.m; sourceTree = ""; }; + 43A536E511DBE3B9004A1712 /* SHKReadItLater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKReadItLater.h; sourceTree = ""; }; + 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKReadItLater.m; sourceTree = ""; }; + 43A536E811DBE3B9004A1712 /* SHKTwitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKTwitter.h; sourceTree = ""; }; + 43A536E911DBE3B9004A1712 /* SHKTwitter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTwitter.m; sourceTree = ""; }; + 43A536EA11DBE3B9004A1712 /* SHKTwitterForm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKTwitterForm.h; sourceTree = ""; }; + 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTwitterForm.m; sourceTree = ""; }; + 43A536EC11DBE3B9004A1712 /* SHKConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKConfig.h; sourceTree = ""; }; + 43A536EE11DBE3B9004A1712 /* SHKActionSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKActionSheet.h; sourceTree = ""; }; + 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKActionSheet.m; sourceTree = ""; }; + 43A536F011DBE3B9004A1712 /* SHKActivityIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKActivityIndicator.h; sourceTree = ""; }; + 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKActivityIndicator.m; sourceTree = ""; }; + 43A536F211DBE3B9004A1712 /* SHKFormController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFormController.h; sourceTree = ""; }; + 43A536F311DBE3B9004A1712 /* SHKFormController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFormController.m; sourceTree = ""; }; + 43A536F411DBE3B9004A1712 /* SHKFormFieldCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFormFieldCell.h; sourceTree = ""; }; + 43A536F511DBE3B9004A1712 /* SHKFormFieldCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFormFieldCell.m; sourceTree = ""; }; + 43A536F611DBE3B9004A1712 /* SHKFormFieldSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFormFieldSettings.h; sourceTree = ""; }; + 43A536F711DBE3B9004A1712 /* SHKFormFieldSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFormFieldSettings.m; sourceTree = ""; }; + 43A536F811DBE3B9004A1712 /* SHKNavController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKNavController.h; sourceTree = ""; }; + 43A536F911DBE3B9004A1712 /* SHKNavController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKNavController.m; sourceTree = ""; }; + 43A536FA11DBE3B9004A1712 /* SHKOAuthView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOAuthView.h; sourceTree = ""; }; + 43A536FB11DBE3B9004A1712 /* SHKOAuthView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOAuthView.m; sourceTree = ""; }; + 43A536FC11DBE3B9004A1712 /* SHKShareMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKShareMenu.h; sourceTree = ""; }; + 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKShareMenu.m; sourceTree = ""; }; + 43A536FE11DBE3B9004A1712 /* SHKViewControllerWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKViewControllerWrapper.h; sourceTree = ""; }; + 43A536FF11DBE3B9004A1712 /* SHKViewControllerWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKViewControllerWrapper.m; sourceTree = ""; }; + 43A5382611DBE480004A1712 /* example.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = example.pdf; path = Classes/Example/example.pdf; sourceTree = ""; }; + 43A5382711DBE480004A1712 /* sanFran.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = sanFran.jpg; path = Classes/Example/sanFran.jpg; sourceTree = ""; }; + 43A5382A11DBE493004A1712 /* ExampleShareFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExampleShareFile.h; path = Example/ExampleShareFile.h; sourceTree = ""; }; + 43A5382B11DBE493004A1712 /* ExampleShareFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ExampleShareFile.m; path = Example/ExampleShareFile.m; sourceTree = ""; }; + 43A5382C11DBE493004A1712 /* ExampleShareImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExampleShareImage.h; path = Example/ExampleShareImage.h; sourceTree = ""; }; + 43A5382D11DBE493004A1712 /* ExampleShareImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ExampleShareImage.m; path = Example/ExampleShareImage.m; sourceTree = ""; }; + 43A5382E11DBE493004A1712 /* ExampleShareLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExampleShareLink.h; path = Example/ExampleShareLink.h; sourceTree = ""; }; + 43A5382F11DBE493004A1712 /* ExampleShareLink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ExampleShareLink.m; path = Example/ExampleShareLink.m; sourceTree = ""; }; + 43A5383011DBE493004A1712 /* ExampleShareText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExampleShareText.h; path = Example/ExampleShareText.h; sourceTree = ""; }; + 43A5383111DBE493004A1712 /* ExampleShareText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ExampleShareText.m; path = Example/ExampleShareText.m; sourceTree = ""; }; + 43A5383211DBE493004A1712 /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RootViewController.h; path = Example/RootViewController.h; sourceTree = ""; }; + 43A5383311DBE493004A1712 /* RootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RootViewController.m; path = Example/RootViewController.m; sourceTree = ""; }; + 43A5383411DBE493004A1712 /* ShareKitAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ShareKitAppDelegate.h; path = Example/ShareKitAppDelegate.h; sourceTree = ""; }; + 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ShareKitAppDelegate.m; path = Example/ShareKitAppDelegate.m; sourceTree = ""; }; + 43A53C0711DC07A9004A1712 /* SHKCustomShareMenuCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCustomShareMenuCell.h; sourceTree = ""; }; + 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenuCell.m; sourceTree = ""; }; + 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCustomShareMenu.h; sourceTree = ""; }; + 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenu.m; sourceTree = ""; }; + 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 43EF406D11D3FFF800B1F700 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 8D1107310486CEB800E47090 /* ShareKit-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ShareKit-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, + 2892E4100DC94CBA00A64D0F /* CoreGraphics.framework in Frameworks */, + 4312CF7C11CB33E200E61D7A /* MessageUI.framework in Frameworks */, + 43EF406E11D3FFF800B1F700 /* Security.framework in Frameworks */, + 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + 43A5367111DBE3B9004A1712 /* ShareKit */, + 4362EB3311B9937300E3DB3A /* Example Project */, + ); + path = Classes; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 1D6058910D05DD3D006BFB54 /* ShareKit.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = CustomTemplate; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 28A0AAE50D9B0CCF005BE974 /* ShareKit_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 43A5382611DBE480004A1712 /* example.pdf */, + 43A5382711DBE480004A1712 /* sanFran.jpg */, + 28F335F01007B36200424DE2 /* RootViewController.xib */, + 28AD735F0D9D9599002E5188 /* MainWindow.xib */, + 8D1107310486CEB800E47090 /* ShareKit-Info.plist */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, + 1D30AB110D05D00D00671497 /* Foundation.framework */, + 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */, + 4312CF7B11CB33E200E61D7A /* MessageUI.framework */, + 43EF406D11D3FFF800B1F700 /* Security.framework */, + 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4362EB3311B9937300E3DB3A /* Example Project */ = { + isa = PBXGroup; + children = ( + 43A5382A11DBE493004A1712 /* ExampleShareFile.h */, + 43A5382B11DBE493004A1712 /* ExampleShareFile.m */, + 43A5382C11DBE493004A1712 /* ExampleShareImage.h */, + 43A5382D11DBE493004A1712 /* ExampleShareImage.m */, + 43A5382E11DBE493004A1712 /* ExampleShareLink.h */, + 43A5382F11DBE493004A1712 /* ExampleShareLink.m */, + 43A5383011DBE493004A1712 /* ExampleShareText.h */, + 43A5383111DBE493004A1712 /* ExampleShareText.m */, + 43A5383211DBE493004A1712 /* RootViewController.h */, + 43A5383311DBE493004A1712 /* RootViewController.m */, + 43A5383411DBE493004A1712 /* ShareKitAppDelegate.h */, + 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */, + ); + name = "Example Project"; + sourceTree = ""; + }; + 43A5367111DBE3B9004A1712 /* ShareKit */ = { + isa = PBXGroup; + children = ( + 43A536EC11DBE3B9004A1712 /* SHKConfig.h */, + 43A536AD11DBE3B9004A1712 /* Customize UI */, + 43A5367211DBE3B9004A1712 /* Core */, + 43A536B511DBE3B9004A1712 /* Sharers */, + 43A536ED11DBE3B9004A1712 /* UI */, + 43A536B211DBE3B9004A1712 /* Reachability */, + ); + path = ShareKit; + sourceTree = ""; + }; + 43A5367211DBE3B9004A1712 /* Core */ = { + isa = PBXGroup; + children = ( + 43A536AC11DBE3B9004A1712 /* SHKSharers.plist */, + 43A536A611DBE3B9004A1712 /* SHK.h */, + 43A536A711DBE3B9004A1712 /* SHK.m */, + 43A536A811DBE3B9004A1712 /* SHKItem.h */, + 43A536A911DBE3B9004A1712 /* SHKItem.m */, + 43A536AA11DBE3B9004A1712 /* SHKOfflineSharer.h */, + 43A536AB11DBE3B9004A1712 /* SHKOfflineSharer.m */, + 43A5367311DBE3B9004A1712 /* Base Sharer Classes */, + 43A5367811DBE3B9004A1712 /* Categories */, + 43A5367B11DBE3B9004A1712 /* Helpers */, + ); + path = Core; + sourceTree = ""; + }; + 43A5367311DBE3B9004A1712 /* Base Sharer Classes */ = { + isa = PBXGroup; + children = ( + 43A5367411DBE3B9004A1712 /* SHKOAuthSharer.h */, + 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */, + 43A5367611DBE3B9004A1712 /* SHKSharer.h */, + 43A5367711DBE3B9004A1712 /* SHKSharer.m */, + ); + path = "Base Sharer Classes"; + sourceTree = ""; + }; + 43A5367811DBE3B9004A1712 /* Categories */ = { + isa = PBXGroup; + children = ( + 43A5367911DBE3B9004A1712 /* UIWebView+SHK.h */, + 43A5367A11DBE3B9004A1712 /* UIWebView+SHK.m */, + ); + path = Categories; + sourceTree = ""; + }; + 43A5367B11DBE3B9004A1712 /* Helpers */ = { + isa = PBXGroup; + children = ( + 43A5367C11DBE3B9004A1712 /* Keychain */, + 43A5367F11DBE3B9004A1712 /* OAuth */, + 43A536A411DBE3B9004A1712 /* SHKRequest.h */, + 43A536A511DBE3B9004A1712 /* SHKRequest.m */, + ); + path = Helpers; + sourceTree = ""; + }; + 43A5367C11DBE3B9004A1712 /* Keychain */ = { + isa = PBXGroup; + children = ( + 43A5367D11DBE3B9004A1712 /* SFHFKeychainUtils.h */, + 43A5367E11DBE3B9004A1712 /* SFHFKeychainUtils.m */, + ); + path = Keychain; + sourceTree = ""; + }; + 43A5367F11DBE3B9004A1712 /* OAuth */ = { + isa = PBXGroup; + children = ( + 43A5368011DBE3B9004A1712 /* Categories */, + 43A5368711DBE3B9004A1712 /* Crytpo */, + 43A5368E11DBE3B9004A1712 /* OAAsynchronousDataFetcher.h */, + 43A5368F11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m */, + 43A5369011DBE3B9004A1712 /* OAConsumer.h */, + 43A5369111DBE3B9004A1712 /* OAConsumer.m */, + 43A5369211DBE3B9004A1712 /* OADataFetcher.h */, + 43A5369311DBE3B9004A1712 /* OADataFetcher.m */, + 43A5369411DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.h */, + 43A5369511DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.m */, + 43A5369611DBE3B9004A1712 /* OAMutableURLRequest.h */, + 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */, + 43A5369811DBE3B9004A1712 /* OAPlaintextSignatureProvider.h */, + 43A5369911DBE3B9004A1712 /* OAPlaintextSignatureProvider.m */, + 43A5369A11DBE3B9004A1712 /* OAProblem.h */, + 43A5369B11DBE3B9004A1712 /* OAProblem.m */, + 43A5369C11DBE3B9004A1712 /* OARequestParameter.h */, + 43A5369D11DBE3B9004A1712 /* OARequestParameter.m */, + 43A5369E11DBE3B9004A1712 /* OAServiceTicket.h */, + 43A5369F11DBE3B9004A1712 /* OAServiceTicket.m */, + 43A536A011DBE3B9004A1712 /* OASignatureProviding.h */, + 43A536A111DBE3B9004A1712 /* OAToken.h */, + 43A536A211DBE3B9004A1712 /* OAToken.m */, + 43A536A311DBE3B9004A1712 /* OAuthConsumer.h */, + ); + path = OAuth; + sourceTree = ""; + }; + 43A5368011DBE3B9004A1712 /* Categories */ = { + isa = PBXGroup; + children = ( + 43A5368111DBE3B9004A1712 /* NSMutableURLRequest+Parameters.h */, + 43A5368211DBE3B9004A1712 /* NSMutableURLRequest+Parameters.m */, + 43A5368311DBE3B9004A1712 /* NSString+URLEncoding.h */, + 43A5368411DBE3B9004A1712 /* NSString+URLEncoding.m */, + 43A5368511DBE3B9004A1712 /* NSURL+Base.h */, + 43A5368611DBE3B9004A1712 /* NSURL+Base.m */, + ); + path = Categories; + sourceTree = ""; + }; + 43A5368711DBE3B9004A1712 /* Crytpo */ = { + isa = PBXGroup; + children = ( + 43A5368811DBE3B9004A1712 /* Base64Transcoder.c */, + 43A5368911DBE3B9004A1712 /* Base64Transcoder.h */, + 43A5368A11DBE3B9004A1712 /* hmac.c */, + 43A5368B11DBE3B9004A1712 /* hmac.h */, + 43A5368C11DBE3B9004A1712 /* sha1.c */, + 43A5368D11DBE3B9004A1712 /* sha1.h */, + ); + path = Crytpo; + sourceTree = ""; + }; + 43A536AD11DBE3B9004A1712 /* Customize UI */ = { + isa = PBXGroup; + children = ( + 43A53C0B11DC0835004A1712 /* Form */, + 43A53C0A11DC080C004A1712 /* Share Menu */, + ); + path = "Customize UI"; + sourceTree = ""; + }; + 43A536B211DBE3B9004A1712 /* Reachability */ = { + isa = PBXGroup; + children = ( + 43A536B311DBE3B9004A1712 /* Reachability.h */, + 43A536B411DBE3B9004A1712 /* Reachability.m */, + ); + path = Reachability; + sourceTree = ""; + }; + 43A536B511DBE3B9004A1712 /* Sharers */ = { + isa = PBXGroup; + children = ( + 43A536B611DBE3B9004A1712 /* Actions */, + 43A536C011DBE3B9004A1712 /* Services */, + ); + path = Sharers; + sourceTree = ""; + }; + 43A536B611DBE3B9004A1712 /* Actions */ = { + isa = PBXGroup; + children = ( + 43A536B711DBE3B9004A1712 /* Copy */, + 43A536BA11DBE3B9004A1712 /* Email */, + 43A536BD11DBE3B9004A1712 /* Open in Safari */, + ); + path = Actions; + sourceTree = ""; + }; + 43A536B711DBE3B9004A1712 /* Copy */ = { + isa = PBXGroup; + children = ( + 43A536B811DBE3B9004A1712 /* SHKCopy.h */, + 43A536B911DBE3B9004A1712 /* SHKCopy.m */, + ); + path = Copy; + sourceTree = ""; + }; + 43A536BA11DBE3B9004A1712 /* Email */ = { + isa = PBXGroup; + children = ( + 43A536BB11DBE3B9004A1712 /* SHKMail.h */, + 43A536BC11DBE3B9004A1712 /* SHKMail.m */, + ); + path = Email; + sourceTree = ""; + }; + 43A536BD11DBE3B9004A1712 /* Open in Safari */ = { + isa = PBXGroup; + children = ( + 43A536BE11DBE3B9004A1712 /* SHKSafari.h */, + 43A536BF11DBE3B9004A1712 /* SHKSafari.m */, + ); + path = "Open in Safari"; + sourceTree = ""; + }; + 43A536C011DBE3B9004A1712 /* Services */ = { + isa = PBXGroup; + children = ( + 43A536C111DBE3B9004A1712 /* Delicious */, + 43A536C411DBE3B9004A1712 /* Facebook */, + 43A536DE11DBE3B9004A1712 /* Google Reader */, + 43A536E111DBE3B9004A1712 /* Pinboard */, + 43A536E411DBE3B9004A1712 /* Read It Later */, + 43A536E711DBE3B9004A1712 /* Twitter */, + ); + path = Services; + sourceTree = ""; + }; + 43A536C111DBE3B9004A1712 /* Delicious */ = { + isa = PBXGroup; + children = ( + 43A536C211DBE3B9004A1712 /* SHKDelicious.h */, + 43A536C311DBE3B9004A1712 /* SHKDelicious.m */, + ); + path = Delicious; + sourceTree = ""; + }; + 43A536C411DBE3B9004A1712 /* Facebook */ = { + isa = PBXGroup; + children = ( + 43A536C511DBE3B9004A1712 /* FBConnect */, + 43A536DC11DBE3B9004A1712 /* SHKFacebook.h */, + 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */, + ); + path = Facebook; + sourceTree = ""; + }; + 43A536C511DBE3B9004A1712 /* FBConnect */ = { + isa = PBXGroup; + children = ( + 43A536C611DBE3B9004A1712 /* FBConnect.bundle */, + 43A536C711DBE3B9004A1712 /* FBConnect.h */, + 43A536C811DBE3B9004A1712 /* FBConnectGlobal.h */, + 43A536C911DBE3B9004A1712 /* FBConnectGlobal.m */, + 43A536CA11DBE3B9004A1712 /* FBDialog.h */, + 43A536CB11DBE3B9004A1712 /* FBDialog.m */, + 43A536CC11DBE3B9004A1712 /* FBFeedDialog.h */, + 43A536CD11DBE3B9004A1712 /* FBFeedDialog.m */, + 43A536CE11DBE3B9004A1712 /* FBLoginButton.h */, + 43A536CF11DBE3B9004A1712 /* FBLoginButton.m */, + 43A536D011DBE3B9004A1712 /* FBLoginDialog.h */, + 43A536D111DBE3B9004A1712 /* FBLoginDialog.m */, + 43A536D211DBE3B9004A1712 /* FBPermissionDialog.h */, + 43A536D311DBE3B9004A1712 /* FBPermissionDialog.m */, + 43A536D411DBE3B9004A1712 /* FBRequest.h */, + 43A536D511DBE3B9004A1712 /* FBRequest.m */, + 43A536D611DBE3B9004A1712 /* FBSession.h */, + 43A536D711DBE3B9004A1712 /* FBSession.m */, + 43A536D811DBE3B9004A1712 /* FBStreamDialog.h */, + 43A536D911DBE3B9004A1712 /* FBStreamDialog.m */, + 43A536DA11DBE3B9004A1712 /* FBXMLHandler.h */, + 43A536DB11DBE3B9004A1712 /* FBXMLHandler.m */, + ); + path = FBConnect; + sourceTree = ""; + }; + 43A536DE11DBE3B9004A1712 /* Google Reader */ = { + isa = PBXGroup; + children = ( + 43A536DF11DBE3B9004A1712 /* SHKGoogleReader.h */, + 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */, + ); + path = "Google Reader"; + sourceTree = ""; + }; + 43A536E111DBE3B9004A1712 /* Pinboard */ = { + isa = PBXGroup; + children = ( + 43A536E211DBE3B9004A1712 /* SHKPinboard.h */, + 43A536E311DBE3B9004A1712 /* SHKPinboard.m */, + ); + path = Pinboard; + sourceTree = ""; + }; + 43A536E411DBE3B9004A1712 /* Read It Later */ = { + isa = PBXGroup; + children = ( + 43A536E511DBE3B9004A1712 /* SHKReadItLater.h */, + 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */, + ); + path = "Read It Later"; + sourceTree = ""; + }; + 43A536E711DBE3B9004A1712 /* Twitter */ = { + isa = PBXGroup; + children = ( + 43A536E811DBE3B9004A1712 /* SHKTwitter.h */, + 43A536E911DBE3B9004A1712 /* SHKTwitter.m */, + 43A536EA11DBE3B9004A1712 /* SHKTwitterForm.h */, + 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */, + ); + path = Twitter; + sourceTree = ""; + }; + 43A536ED11DBE3B9004A1712 /* UI */ = { + isa = PBXGroup; + children = ( + 43A536EE11DBE3B9004A1712 /* SHKActionSheet.h */, + 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */, + 43A536F011DBE3B9004A1712 /* SHKActivityIndicator.h */, + 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */, + 43A536F211DBE3B9004A1712 /* SHKFormController.h */, + 43A536F311DBE3B9004A1712 /* SHKFormController.m */, + 43A536F411DBE3B9004A1712 /* SHKFormFieldCell.h */, + 43A536F511DBE3B9004A1712 /* SHKFormFieldCell.m */, + 43A536F611DBE3B9004A1712 /* SHKFormFieldSettings.h */, + 43A536F711DBE3B9004A1712 /* SHKFormFieldSettings.m */, + 43A536FC11DBE3B9004A1712 /* SHKShareMenu.h */, + 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */, + 43A536FA11DBE3B9004A1712 /* SHKOAuthView.h */, + 43A536FB11DBE3B9004A1712 /* SHKOAuthView.m */, + 43A536F811DBE3B9004A1712 /* SHKNavController.h */, + 43A536F911DBE3B9004A1712 /* SHKNavController.m */, + 43A536FE11DBE3B9004A1712 /* SHKViewControllerWrapper.h */, + 43A536FF11DBE3B9004A1712 /* SHKViewControllerWrapper.m */, + ); + path = UI; + sourceTree = ""; + }; + 43A53C0A11DC080C004A1712 /* Share Menu */ = { + isa = PBXGroup; + children = ( + 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */, + 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */, + 43A53C0711DC07A9004A1712 /* SHKCustomShareMenuCell.h */, + 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */, + ); + name = "Share Menu"; + sourceTree = ""; + }; + 43A53C0B11DC0835004A1712 /* Form */ = { + isa = PBXGroup; + children = ( + 43A536AE11DBE3B9004A1712 /* SHKCustomFormController.h */, + 43A536AF11DBE3B9004A1712 /* SHKCustomFormController.m */, + 43A536B011DBE3B9004A1712 /* SHKCustomFormFieldCell.h */, + 43A536B111DBE3B9004A1712 /* SHKCustomFormFieldCell.m */, + ); + name = Form; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1D6058900D05DD3D006BFB54 /* ShareKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "ShareKit" */; + buildPhases = ( + 1D60588D0D05DD3D006BFB54 /* Resources */, + 1D60588E0D05DD3D006BFB54 /* Sources */, + 1D60588F0D05DD3D006BFB54 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ShareKit; + productName = ShareKit; + productReference = 1D6058910D05DD3D006BFB54 /* ShareKit.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ShareKit" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + en, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1D6058900D05DD3D006BFB54 /* ShareKit */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1D60588D0D05DD3D006BFB54 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */, + 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */, + 43A5371811DBE3B9004A1712 /* SHKSharers.plist in Resources */, + 43A5372011DBE3B9004A1712 /* FBConnect.bundle in Resources */, + 43A5382811DBE480004A1712 /* example.pdf in Resources */, + 43A5382911DBE480004A1712 /* sanFran.jpg in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1D60588E0D05DD3D006BFB54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589B0D05DD56006BFB54 /* main.m in Sources */, + 43A5370011DBE3B9004A1712 /* SHKOAuthSharer.m in Sources */, + 43A5370111DBE3B9004A1712 /* SHKSharer.m in Sources */, + 43A5370211DBE3B9004A1712 /* UIWebView+SHK.m in Sources */, + 43A5370311DBE3B9004A1712 /* SFHFKeychainUtils.m in Sources */, + 43A5370411DBE3B9004A1712 /* NSMutableURLRequest+Parameters.m in Sources */, + 43A5370511DBE3B9004A1712 /* NSString+URLEncoding.m in Sources */, + 43A5370611DBE3B9004A1712 /* NSURL+Base.m in Sources */, + 43A5370711DBE3B9004A1712 /* Base64Transcoder.c in Sources */, + 43A5370811DBE3B9004A1712 /* hmac.c in Sources */, + 43A5370911DBE3B9004A1712 /* sha1.c in Sources */, + 43A5370A11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m in Sources */, + 43A5370B11DBE3B9004A1712 /* OAConsumer.m in Sources */, + 43A5370C11DBE3B9004A1712 /* OADataFetcher.m in Sources */, + 43A5370D11DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.m in Sources */, + 43A5370E11DBE3B9004A1712 /* OAMutableURLRequest.m in Sources */, + 43A5370F11DBE3B9004A1712 /* OAPlaintextSignatureProvider.m in Sources */, + 43A5371011DBE3B9004A1712 /* OAProblem.m in Sources */, + 43A5371111DBE3B9004A1712 /* OARequestParameter.m in Sources */, + 43A5371211DBE3B9004A1712 /* OAServiceTicket.m in Sources */, + 43A5371311DBE3B9004A1712 /* OAToken.m in Sources */, + 43A5371411DBE3B9004A1712 /* SHKRequest.m in Sources */, + 43A5371511DBE3B9004A1712 /* SHK.m in Sources */, + 43A5371611DBE3B9004A1712 /* SHKItem.m in Sources */, + 43A5371711DBE3B9004A1712 /* SHKOfflineSharer.m in Sources */, + 43A5371911DBE3B9004A1712 /* SHKCustomFormController.m in Sources */, + 43A5371A11DBE3B9004A1712 /* SHKCustomFormFieldCell.m in Sources */, + 43A5371B11DBE3B9004A1712 /* Reachability.m in Sources */, + 43A5371C11DBE3B9004A1712 /* SHKCopy.m in Sources */, + 43A5371D11DBE3B9004A1712 /* SHKMail.m in Sources */, + 43A5371E11DBE3B9004A1712 /* SHKSafari.m in Sources */, + 43A5371F11DBE3B9004A1712 /* SHKDelicious.m in Sources */, + 43A5372111DBE3B9004A1712 /* FBConnectGlobal.m in Sources */, + 43A5372211DBE3B9004A1712 /* FBDialog.m in Sources */, + 43A5372311DBE3B9004A1712 /* FBFeedDialog.m in Sources */, + 43A5372411DBE3B9004A1712 /* FBLoginButton.m in Sources */, + 43A5372511DBE3B9004A1712 /* FBLoginDialog.m in Sources */, + 43A5372611DBE3B9004A1712 /* FBPermissionDialog.m in Sources */, + 43A5372711DBE3B9004A1712 /* FBRequest.m in Sources */, + 43A5372811DBE3B9004A1712 /* FBSession.m in Sources */, + 43A5372911DBE3B9004A1712 /* FBStreamDialog.m in Sources */, + 43A5372A11DBE3B9004A1712 /* FBXMLHandler.m in Sources */, + 43A5372B11DBE3B9004A1712 /* SHKFacebook.m in Sources */, + 43A5372C11DBE3B9004A1712 /* SHKGoogleReader.m in Sources */, + 43A5372D11DBE3B9004A1712 /* SHKPinboard.m in Sources */, + 43A5372E11DBE3B9004A1712 /* SHKReadItLater.m in Sources */, + 43A5372F11DBE3B9004A1712 /* SHKTwitter.m in Sources */, + 43A5373011DBE3B9004A1712 /* SHKTwitterForm.m in Sources */, + 43A5373111DBE3B9004A1712 /* SHKActionSheet.m in Sources */, + 43A5373211DBE3B9004A1712 /* SHKActivityIndicator.m in Sources */, + 43A5373311DBE3B9004A1712 /* SHKFormController.m in Sources */, + 43A5373411DBE3B9004A1712 /* SHKFormFieldCell.m in Sources */, + 43A5373511DBE3B9004A1712 /* SHKFormFieldSettings.m in Sources */, + 43A5373611DBE3B9004A1712 /* SHKNavController.m in Sources */, + 43A5373711DBE3B9004A1712 /* SHKOAuthView.m in Sources */, + 43A5373811DBE3B9004A1712 /* SHKShareMenu.m in Sources */, + 43A5373911DBE3B9004A1712 /* SHKViewControllerWrapper.m in Sources */, + 43A5383611DBE493004A1712 /* ExampleShareFile.m in Sources */, + 43A5383711DBE493004A1712 /* ExampleShareImage.m in Sources */, + 43A5383811DBE493004A1712 /* ExampleShareLink.m in Sources */, + 43A5383911DBE493004A1712 /* ExampleShareText.m in Sources */, + 43A5383A11DBE493004A1712 /* RootViewController.m in Sources */, + 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */, + 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */, + 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1D6058940D05DD3E006BFB54 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = ShareKit_Prefix.pch; + INFOPLIST_FILE = "ShareKit-Info.plist"; + PRODUCT_NAME = ShareKit; + SDKROOT = iphoneos4.0; + }; + name = Debug; + }; + 1D6058950D05DD3E006BFB54 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = ShareKit_Prefix.pch; + INFOPLIST_FILE = "ShareKit-Info.plist"; + PRODUCT_NAME = ShareKit; + SDKROOT = iphoneos4.0; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = iphoneos3.1.3; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + PREBINDING = NO; + SDKROOT = iphoneos3.1.3; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "ShareKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D6058940D05DD3E006BFB54 /* Debug */, + 1D6058950D05DD3E006BFB54 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ShareKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/ShareKit_Prefix.pch b/ShareKit_Prefix.pch new file mode 100644 index 00000000..b3c02d5f --- /dev/null +++ b/ShareKit_Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header for all source files of the 'ShareKit' target in the 'ShareKit' project +// +#import + +#ifndef __IPHONE_3_0 +#warning "This project uses features only available in iPhone SDK 3.0 and later." +#endif + + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/main.m b/main.m new file mode 100644 index 00000000..4018ee81 --- /dev/null +++ b/main.m @@ -0,0 +1,17 @@ +// +// main.m +// ShareKit +// +// Created by Nathan Weiner on 6/4/10. +// Copyright Idea Shower, LLC 2010. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) { + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + int retVal = UIApplicationMain(argc, argv, nil, nil); + [pool release]; + return retVal; +} From 812fe20c0dc480b0affdc0a00ca5d564b8bdf812 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Thu, 8 Jul 2010 09:30:04 -0700 Subject: [PATCH 02/50] Revising README for clarity --- README | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/README b/README index b938907e..a1f6a406 100644 --- a/README +++ b/README @@ -1,9 +1,22 @@ -The project hosted on github is for contributions and ongoing development. It should not be used in existing projects. +The code hosted here on github is for ongoing development and contributions and may contain untested code. Please use a stable release from http://getsharekit.com for use in your own app. -For stable releases, please visit: -http://getsharekit.com +*** + +To download a stable release visits: +http://getsharekit.com/install -For documentation and install instructions, please visit: +Installation instructions: http://getsharekit.com/install +How to add new services: +http://getsharekit.com/add + +How to customize the look of ShareKit: +http://getsharekit.com/customize + +Full documentation: +http://getsharekit.com/docs + *** + +Follow @IdeaShower or http://getsharekit.com/blog for updates From d37fe7b0219e1f891b002dd1407252d869f0b5be Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Thu, 8 Jul 2010 09:32:28 -0700 Subject: [PATCH 03/50] README typo --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index a1f6a406..87f0bac7 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ The code hosted here on github is for ongoing development and contributions and *** -To download a stable release visits: +To download a stable release visit: http://getsharekit.com/install Installation instructions: From cbeff2618f5d01019dbe3d68c56d32f743dbbb37 Mon Sep 17 00:00:00 2001 From: Sean Murphy Date: Fri, 9 Jul 2010 09:08:36 +0800 Subject: [PATCH 04/50] Modified SHKRequest to interpret a 201 HTTP status code (Created) as successful --- Classes/ShareKit/Core/Helpers/SHKRequest.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Core/Helpers/SHKRequest.m b/Classes/ShareKit/Core/Helpers/SHKRequest.m index 243e6ccd..7d619f28 100644 --- a/Classes/ShareKit/Core/Helpers/SHKRequest.m +++ b/Classes/ShareKit/Core/Helpers/SHKRequest.m @@ -131,7 +131,7 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)err - (void)finish { - self.success = response.statusCode == 200; + self.success = (response.statusCode == 200 || response.statusCode == 201); if ([delegate respondsToSelector:isFinishedSelector]) [delegate performSelector:isFinishedSelector withObject:self]; From 9c60e468bbb6e7e17e78835ae7aa2ee5aa16fe37 Mon Sep 17 00:00:00 2001 From: Sean Murphy Date: Fri, 9 Jul 2010 09:10:41 +0800 Subject: [PATCH 05/50] Added Instapaper sharer --- Classes/ShareKit/Core/SHKSharers.plist | 1 + .../Services/Instapaper/SHKInstapaper.h | 34 ++++ .../Services/Instapaper/SHKInstapaper.m | 171 ++++++++++++++++++ ShareKit.xcodeproj/project.pbxproj | 14 ++ 4 files changed, 220 insertions(+) create mode 100644 Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h create mode 100644 Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m diff --git a/Classes/ShareKit/Core/SHKSharers.plist b/Classes/ShareKit/Core/SHKSharers.plist index 0d20aac9..c50d11f0 100644 --- a/Classes/ShareKit/Core/SHKSharers.plist +++ b/Classes/ShareKit/Core/SHKSharers.plist @@ -16,6 +16,7 @@ SHKGoogleReader SHKFacebook SHKReadItLater + SHKInstapaper diff --git a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h new file mode 100644 index 00000000..5c769162 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h @@ -0,0 +1,34 @@ +// +// SHKInstapaper.h +// ShareKit +// +// Created by Sean Murphy on 7/8/10. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" + +@interface SHKInstapaper : SHKSharer { + +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m new file mode 100644 index 00000000..62488bab --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m @@ -0,0 +1,171 @@ +// +// SHKInstapaper.m +// ShareKit +// +// Created by Sean Murphy on 7/8/10. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKInstapaper.h" + +static NSString * const kInstapaperAuthenticationURL = @"https://www.instapaper.com/api/authenticate"; +static NSString * const kInstapaperSharingURL = @"https://www.instapaper.com/api/add"; + +@implementation SHKInstapaper + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle +{ + return @"Instapaper"; +} + ++ (BOOL)canShareURL +{ + return YES; +} + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + ++ (BOOL)canShare +{ + return YES; +} + +- (BOOL)shouldAutoShare +{ + return [[NSUserDefaults standardUserDefaults] boolForKey:[NSString stringWithFormat:@"%@_shouldAutoShare", [self sharerId]]]; +} + +#pragma mark - +#pragma mark Authorization + +- (NSString *)authorizationFormCaption +{ + return @"Set up a free account at http://instapaper.com"; +} + +- (void)authorizationFormValidate:(SHKFormController *)form +{ + // Display an activity indicator + if (!quiet) + [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + + + // Authorize the user through the server + NSDictionary *formValues = [form formValues]; + + NSString *params = [NSMutableString stringWithFormat:@"username=%@&password=%@", + SHKEncode([formValues objectForKey:@"username"]), + SHKEncode([formValues objectForKey:@"password"]) + ]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:kInstapaperAuthenticationURL] + params:params + delegate:self + isFinishedSelector:@selector(authFinished:) + method:@"POST" + autostart:YES] autorelease]; + + self.pendingForm = form; +} + +- (void)authFinished:(SHKRequest *)aRequest +{ + [[SHKActivityIndicator currentIndicator] hide]; + + if (aRequest.success) + [pendingForm saveForm]; + + else { + NSString *errorMessage = nil; + if (aRequest.response.statusCode == 403) + errorMessage = @"Invalid username or password."; + else + errorMessage = @"The service encountered an error. Please try again later."; + + [[[[UIAlertView alloc] initWithTitle:@"Login Error" + message:errorMessage + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + } +} + +#pragma mark - +#pragma mark Share Form + +- (NSArray *)shareFormFieldsForType:(SHKShareType)type +{ + // Instapaper will automatically obtain a title for the URL, so we do not need + // any other information. + return nil; +} + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send +{ + if ([self validateItem]) { + NSString *params = [NSMutableString stringWithFormat:@"url=%@&username=%@&password=%@", + SHKEncodeURL(self.item.URL), + SHKEncode([self getAuthValueForKey:@"username"]), + SHKEncode([self getAuthValueForKey:@"password"])]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:kInstapaperSharingURL] + params:params + delegate:self + isFinishedSelector:@selector(sendFinished:) + method:@"POST" + autostart:YES] autorelease]; + + // Notify delegate + [self sendDidStart]; + + return YES; + } + + return NO; +} + +- (void)sendFinished:(SHKRequest *)aRequest +{ + if (!aRequest.success) { + if (aRequest.response.statusCode == 403) { + [self sendDidFailWithError:[SHK error:@"Invalid username or password."] shouldRelogin:YES]; + return; + } + else if (aRequest.response.statusCode == 500) { + [self sendDidFailWithError:[SHK error:@"The service encountered an error. Please try again later."]]; + return; + } + + [self sendDidFailWithError:[SHK error:@"There was a problem saving to Instapaper."]]; + return; + } + + [self sendDidFinish]; +} + +@end diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index 14b4b2cb..e9ef771b 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 2892E4100DC94CBA00A64D0F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */; }; 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD735F0D9D9599002E5188 /* MainWindow.xib */; }; 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28F335F01007B36200424DE2 /* RootViewController.xib */; }; + 3D384B5311E6AD2000C8056C /* SHKInstapaper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D384B5111E6AD2000C8056C /* SHKInstapaper.m */; }; 4312CF7C11CB33E200E61D7A /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4312CF7B11CB33E200E61D7A /* MessageUI.framework */; }; 43A5370011DBE3B9004A1712 /* SHKOAuthSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; }; 43A5370111DBE3B9004A1712 /* SHKSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; }; @@ -95,6 +96,8 @@ 28AD735F0D9D9599002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 28F335F01007B36200424DE2 /* RootViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RootViewController.xib; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 3D384B5111E6AD2000C8056C /* SHKInstapaper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SHKInstapaper.m; path = Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m; sourceTree = SOURCE_ROOT; }; + 3D384B5211E6AD2000C8056C /* SHKInstapaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SHKInstapaper.h; path = Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h; sourceTree = SOURCE_ROOT; }; 4312CF7B11CB33E200E61D7A /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; 43A5367411DBE3B9004A1712 /* SHKOAuthSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOAuthSharer.h; sourceTree = ""; }; 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOAuthSharer.m; sourceTree = ""; }; @@ -317,6 +320,15 @@ name = Frameworks; sourceTree = ""; }; + 3D384B4D11E6ACF700C8056C /* Instapaper */ = { + isa = PBXGroup; + children = ( + 3D384B5211E6AD2000C8056C /* SHKInstapaper.h */, + 3D384B5111E6AD2000C8056C /* SHKInstapaper.m */, + ); + path = Instapaper; + sourceTree = ""; + }; 4362EB3311B9937300E3DB3A /* Example Project */ = { isa = PBXGroup; children = ( @@ -533,6 +545,7 @@ 43A536C111DBE3B9004A1712 /* Delicious */, 43A536C411DBE3B9004A1712 /* Facebook */, 43A536DE11DBE3B9004A1712 /* Google Reader */, + 3D384B4D11E6ACF700C8056C /* Instapaper */, 43A536E111DBE3B9004A1712 /* Pinboard */, 43A536E411DBE3B9004A1712 /* Read It Later */, 43A536E711DBE3B9004A1712 /* Twitter */, @@ -803,6 +816,7 @@ 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */, 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */, 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */, + 3D384B5311E6AD2000C8056C /* SHKInstapaper.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 69bbcaaee70cd38845e9ee3a91fa6bda64e90528 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Fri, 9 Jul 2010 10:00:01 -0700 Subject: [PATCH 06/50] Cleaned up SHKInstapaper, Modified SHKSharer to support services with optional passwords --- .../Core/Base Sharer Classes/SHKSharer.m | 10 +- Classes/ShareKit/SHKConfig.h | 2 +- .../Services/Instapaper/SHKInstapaper.h | 0 .../Services/Instapaper/SHKInstapaper.m | 5 - .../Sharers/Services/Twitter/SHKTwitter.m | 2 +- Classes/ShareKit/UI/SHKShareMenu.m | 2 +- ShareKit.xcodeproj/nate.mode1v3 | 112 +-- ShareKit.xcodeproj/nate.pbxuser | 858 +++++++----------- ShareKit.xcodeproj/project.pbxproj | 4 +- 9 files changed, 385 insertions(+), 610 deletions(-) mode change 100644 => 100755 Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h mode change 100644 => 100755 Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m index 7d05e77a..ac903819 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m @@ -285,18 +285,18 @@ - (BOOL)isAuthorized if (![[self class] requiresAuthentication]) return YES; - // Default implementation assumes the service needs all values from authorization keys. - // Subclass to customize requirements + // Checks to make sure we just have at least one variable from the authorization form + // If the send request fails it'll reprompt the user for their new login anyway NSString *sharerId = [self sharerId]; NSArray *fields = [self authorizationFormFields]; for (SHKFormFieldSettings *field in fields) { - if (![SHK getAuthValueForKey:field.key forSharer:sharerId]) - return NO; + if ([SHK getAuthValueForKey:field.key forSharer:sharerId] != nil) + return YES; } - return YES; + return NO; } - (BOOL)authorize diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 1976afc4..f7058fe8 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -67,7 +67,7 @@ leaving that decision up to the user. // Flickr -// Read It Later - http://readitlaterlist.com/api/ +// Read It Later - http://readitlaterlist.com/api/?shk #define SHKReadItLaterKey @"" // Twitter - http://dev.twitter.com/apps/new diff --git a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h old mode 100644 new mode 100755 diff --git a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m old mode 100644 new mode 100755 index 62488bab..acada8d9 --- a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m +++ b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m @@ -52,11 +52,6 @@ + (BOOL)canShare return YES; } -- (BOOL)shouldAutoShare -{ - return [[NSUserDefaults standardUserDefaults] boolForKey:[NSString stringWithFormat:@"%@_shouldAutoShare", [self sharerId]]]; -} - #pragma mark - #pragma mark Authorization diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index b22e2544..53a848ba 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -235,7 +235,7 @@ - (void)sendForm:(SHKTwitterForm *)form #pragma mark - - (void)shortenURL -{ +{ if (!quiet) [[SHKActivityIndicator currentIndicator] displayActivity:@"Shortening URL..."]; diff --git a/Classes/ShareKit/UI/SHKShareMenu.m b/Classes/ShareKit/UI/SHKShareMenu.m index 20f806ca..47ee7f2d 100644 --- a/Classes/ShareKit/UI/SHKShareMenu.m +++ b/Classes/ShareKit/UI/SHKShareMenu.m @@ -263,7 +263,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath else { - [objc_getClass([[rowData objectForKey:@"className"] UTF8String]) shareItem:item]; // TODO - make this warning go away + [objc_getClass([[rowData objectForKey:@"className"] UTF8String]) shareItem:item]; [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; } diff --git a/ShareKit.xcodeproj/nate.mode1v3 b/ShareKit.xcodeproj/nate.mode1v3 index 140dff64..bbd2724a 100644 --- a/ShareKit.xcodeproj/nate.mode1v3 +++ b/ShareKit.xcodeproj/nate.mode1v3 @@ -277,9 +277,11 @@ 43A536B511DBE3B9004A1712 43A536B611DBE3B9004A1712 43A536B711DBE3B9004A1712 + 43A536BA11DBE3B9004A1712 43A536C011DBE3B9004A1712 43A536C411DBE3B9004A1712 43A536DE11DBE3B9004A1712 + 43150A8A11E78697008C6B68 43A536E411DBE3B9004A1712 43A536E711DBE3B9004A1712 43A536ED11DBE3B9004A1712 @@ -291,17 +293,16 @@ PBXSmartGroupTreeModuleOutlineStateSelectionKey - 45 - 43 - 33 - 26 + 19 + 15 + 7 2 1 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 208}, {316, 813}} + {{0, 250}, {316, 813}} PBXTopSmartGroupGIDs @@ -320,7 +321,7 @@ 316 RubberWindowFrame - 14 124 1183 872 0 0 1280 1002 + 59 110 1183 872 0 0 1280 1002 Module PBXSmartGroupTreeModule @@ -338,7 +339,7 @@ PBXProjectModuleGUID 1CE0B20306471E060097A5F4 PBXProjectModuleLabel - SHKReadItLater.m + SHKSharer.m PBXSplitModuleInNavigatorKey Split0 @@ -346,11 +347,11 @@ PBXProjectModuleGUID 1CE0B20406471E060097A5F4 PBXProjectModuleLabel - SHKReadItLater.m + SHKSharer.m _historyCapacity 0 bookmark - 439B96B711E2985F00ABE3BF + 43150A9D11E78722008C6B68 history 4362EB6D11B9A14600E3DB3A @@ -376,8 +377,6 @@ 43A53D2011DD221F004A1712 43A53D2111DD221F004A1712 43A53D2E11DD221F004A1712 - 43A53D8C11DD5018004A1712 - 43A53D8D11DD5018004A1712 43B665DD11DD544700BDBA80 43B665F711DD572D00BDBA80 43B665F811DD572D00BDBA80 @@ -385,23 +384,31 @@ 43B665FA11DD572D00BDBA80 43B665FB11DD572D00BDBA80 43B6662611DD57D600BDBA80 - 43B6662D11DD586F00BDBA80 43B6663111DD591600BDBA80 - 43B6667111DE4AB700BDBA80 - 43C3FBA511DE844F002FA9FD 43C3FBA611DE844F002FA9FD - 43C3FBA711DE844F002FA9FD 439B966011E289A200ABE3BF - 439B966611E2909300ABE3BF 439B967B11E2926900ABE3BF - 439B967C11E2926900ABE3BF 439B969E11E295CC00ABE3BF 439B969F11E295CC00ABE3BF 439B96A011E295CC00ABE3BF - 439B96A111E295CC00ABE3BF 439B96A711E2981100ABE3BF - 439B96B611E2985F00ABE3BF - 439B96B311E2984300ABE3BF + 439B96C211E38CED00ABE3BF + 439B96C411E38CED00ABE3BF + 439B96C611E38CED00ABE3BF + 439B975B11E3A4EC00ABE3BF + 439B977211E3A79E00ABE3BF + 439B977411E3A79E00ABE3BF + 439B978611E3B2C500ABE3BF + 439B97C011E3D52A00ABE3BF + 439B97CB11E3D94500ABE3BF + 436A5FCD11E3F1C500622EE8 + 436A5FD211E4128600622EE8 + 43FFF28D11E6CD9E00F9E529 + 43FFF28E11E6CD9E00F9E529 + 43150A9011E78702008C6B68 + 43150A9111E78702008C6B68 + 43150A9211E78702008C6B68 + 436A60AF11E510BD00622EE8 SplitCount @@ -415,7 +422,7 @@ Frame {{0, 0}, {845, 826}} RubberWindowFrame - 14 124 1183 872 0 0 1280 1002 + 59 110 1183 872 0 0 1280 1002 Module PBXNavigatorGroup @@ -435,7 +442,7 @@ Frame {{0, 831}, {845, 0}} RubberWindowFrame - 14 124 1183 872 0 0 1280 1002 + 59 110 1183 872 0 0 1280 1002 Module XCDetailModule @@ -459,9 +466,9 @@ TableOfContents - 439B964011E288A300ABE3BF + 43150A8711E7862F008C6B68 1CE0B1FE06471DED0097A5F4 - 439B964111E288A300ABE3BF + 43150A8811E7862F008C6B68 1CE0B20306471E060097A5F4 1CE0B20506471E060097A5F4 @@ -599,17 +606,16 @@ 5 WindowOrderList - 439B96B011E2983100ABE3BF - 439B964D11E288A300ABE3BF - 439B964E11E288A300ABE3BF + 43150A9E11E78722008C6B68 + 43150A9B11E78702008C6B68 + 43150A9C11E78702008C6B68 + 1C78EAAD065D492600B07095 1CD10A99069EF8BA00B06720 4362EB7711B9A14600E3DB3A - 1C530D57069F1CE1000CFCEE - 1C78EAAD065D492600B07095 /Users/nate/Documents/Development/ShareKit/Working Copy/ShareKit.xcodeproj WindowString - 14 124 1183 872 0 0 1280 1002 + 59 110 1183 872 0 0 1280 1002 WindowToolsV3 @@ -630,7 +636,7 @@ PBXProjectModuleGUID 1CD0528F0623707200166675 PBXProjectModuleLabel - SHKTwitterForm.m + StatusBarVisibility @@ -647,8 +653,6 @@ 445pt - BecomeActive - ContentConfiguration PBXProjectModuleGUID @@ -688,7 +692,7 @@ TableOfContents 4362EB7711B9A14600E3DB3A - 439B964211E288A300ABE3BF + 43150A8911E7862F008C6B68 1CD0528F0623707200166675 XCMainBuildResultsModuleGUID @@ -701,7 +705,7 @@ WindowToolGUID 4362EB7711B9A14600E3DB3A WindowToolIsVisible - + FirstTimeWindowDisplayed @@ -810,13 +814,13 @@ TableOfContents 1CD10A99069EF8BA00B06720 - 439B964311E288A300ABE3BF + 43150A9411E78702008C6B68 1C162984064C10D400B95A72 - 439B964411E288A300ABE3BF - 439B964511E288A300ABE3BF - 439B964611E288A300ABE3BF - 439B964711E288A300ABE3BF - 439B964811E288A300ABE3BF + 43150A9511E78702008C6B68 + 43150A9611E78702008C6B68 + 43150A9711E78702008C6B68 + 43150A9811E78702008C6B68 + 43150A9911E78702008C6B68 ToolbarConfiguration xcode.toolbar.config.debugV3 @@ -825,7 +829,7 @@ WindowToolGUID 1CD10A99069EF8BA00B06720 WindowToolIsVisible - + FirstTimeWindowDisplayed @@ -843,14 +847,12 @@ Dock - BecomeActive - ContentConfiguration PBXProjectModuleGUID 1CDD528C0622207200134675 PBXProjectModuleLabel - SHKSharer.m + ExampleShareLink.m StatusBarVisibility @@ -859,7 +861,7 @@ Frame {{0, 0}, {981, 468}} RubberWindowFrame - -1246 94 981 890 -1280 0 1280 1024 + 150 74 981 890 0 0 1280 1002 Module PBXNavigatorGroup @@ -871,6 +873,8 @@ 468pt + BecomeActive + ContentConfiguration PBXProjectModuleGUID @@ -883,7 +887,7 @@ Frame {{0, 473}, {981, 376}} RubberWindowFrame - -1246 94 981 890 -1280 0 1280 1024 + 150 74 981 890 0 0 1280 1002 Module PBXProjectFindModule @@ -906,17 +910,17 @@ TableOfContents 1C530D57069F1CE1000CFCEE - 439B964911E288A300ABE3BF - 439B964A11E288A300ABE3BF + 43FFF28B11E6633F00F9E529 + 43FFF28C11E6633F00F9E529 1CDD528C0622207200134675 1CD0528E0623707200166675 WindowString - -1246 94 981 890 -1280 0 1280 1024 + 150 74 981 890 0 0 1280 1002 WindowToolGUID 1C530D57069F1CE1000CFCEE WindowToolIsVisible - + Identifier @@ -935,8 +939,6 @@ Dock - BecomeActive - ContentConfiguration PBXProjectModuleGUID @@ -972,7 +974,7 @@ TableOfContents 1C78EAAD065D492600B07095 - 439B964B11E288A300ABE3BF + 43150A9A11E78702008C6B68 1C78EAAC065D492600B07095 ToolbarConfiguration @@ -982,7 +984,7 @@ WindowToolGUID 1C78EAAD065D492600B07095 WindowToolIsVisible - + Identifier diff --git a/ShareKit.xcodeproj/nate.pbxuser b/ShareKit.xcodeproj/nate.pbxuser index b0478856..49827e61 100644 --- a/ShareKit.xcodeproj/nate.pbxuser +++ b/ShareKit.xcodeproj/nate.pbxuser @@ -22,7 +22,6 @@ 1D6058900D05DD3D006BFB54 /* ShareKit */, ); breakpoints = ( - 439B96B111E2984200ABE3BF /* SHKSharer.m:417 */, ); codeSenseManager = 4362EB3511B9937300E3DB3A /* Code sense */; executables = ( @@ -87,52 +86,37 @@ PBXFindDataSource_LocationID, ); }; - PBXPerProjectTemplateStateSaveDate = 300055808; - PBXWorkspaceStateSaveDate = 300055808; + PBXPerProjectTemplateStateSaveDate = 300385834; + PBXWorkspaceStateSaveDate = 300385834; }; perUserProjectItems = { + 43150A8511E7862F008C6B68 /* PBXTextBookmark */ = 43150A8511E7862F008C6B68 /* PBXTextBookmark */; + 43150A8611E7862F008C6B68 /* PBXTextBookmark */ = 43150A8611E7862F008C6B68 /* PBXTextBookmark */; + 43150A9011E78702008C6B68 /* PBXTextBookmark */ = 43150A9011E78702008C6B68 /* PBXTextBookmark */; + 43150A9111E78702008C6B68 /* PBXTextBookmark */ = 43150A9111E78702008C6B68 /* PBXTextBookmark */; + 43150A9211E78702008C6B68 /* PBXTextBookmark */ = 43150A9211E78702008C6B68 /* PBXTextBookmark */; + 43150A9311E78702008C6B68 /* PBXTextBookmark */ = 43150A9311E78702008C6B68 /* PBXTextBookmark */; + 43150A9D11E78722008C6B68 /* PBXTextBookmark */ = 43150A9D11E78722008C6B68 /* PBXTextBookmark */; 4362EB6D11B9A14600E3DB3A = 4362EB6D11B9A14600E3DB3A /* PBXTextBookmark */; - 439B963B11E288A300ABE3BF /* PBXTextBookmark */ = 439B963B11E288A300ABE3BF /* PBXTextBookmark */; - 439B963C11E288A300ABE3BF /* PBXTextBookmark */ = 439B963C11E288A300ABE3BF /* PBXTextBookmark */; - 439B963D11E288A300ABE3BF /* PBXTextBookmark */ = 439B963D11E288A300ABE3BF /* PBXTextBookmark */; - 439B963E11E288A300ABE3BF /* PBXTextBookmark */ = 439B963E11E288A300ABE3BF /* PBXTextBookmark */; - 439B963F11E288A300ABE3BF /* PBXTextBookmark */ = 439B963F11E288A300ABE3BF /* PBXTextBookmark */; - 439B965511E2892800ABE3BF /* PBXTextBookmark */ = 439B965511E2892800ABE3BF /* PBXTextBookmark */; - 439B965611E2892800ABE3BF /* PBXTextBookmark */ = 439B965611E2892800ABE3BF /* PBXTextBookmark */; - 439B965711E2892800ABE3BF /* PBXTextBookmark */ = 439B965711E2892800ABE3BF /* PBXTextBookmark */; - 439B965D11E289A000ABE3BF /* PBXTextBookmark */ = 439B965D11E289A000ABE3BF /* PBXTextBookmark */; - 439B965E11E289A000ABE3BF /* PBXTextBookmark */ = 439B965E11E289A000ABE3BF /* PBXTextBookmark */; - 439B965F11E289A000ABE3BF /* PBXTextBookmark */ = 439B965F11E289A000ABE3BF /* PBXTextBookmark */; - 439B966011E289A200ABE3BF /* PBXTextBookmark */ = 439B966011E289A200ABE3BF /* PBXTextBookmark */; - 439B966111E289A200ABE3BF /* PBXTextBookmark */ = 439B966111E289A200ABE3BF /* PBXTextBookmark */; - 439B966211E289A200ABE3BF /* PBXTextBookmark */ = 439B966211E289A200ABE3BF /* PBXTextBookmark */; - 439B966611E2909300ABE3BF /* PBXTextBookmark */ = 439B966611E2909300ABE3BF /* PBXTextBookmark */; - 439B966711E2909300ABE3BF /* PBXTextBookmark */ = 439B966711E2909300ABE3BF /* PBXTextBookmark */; - 439B966811E2909300ABE3BF /* PBXTextBookmark */ = 439B966811E2909300ABE3BF /* PBXTextBookmark */; - 439B966911E2909300ABE3BF /* PBXTextBookmark */ = 439B966911E2909300ABE3BF /* PBXTextBookmark */; - 439B967B11E2926900ABE3BF /* PBXTextBookmark */ = 439B967B11E2926900ABE3BF /* PBXTextBookmark */; - 439B967C11E2926900ABE3BF /* PBXTextBookmark */ = 439B967C11E2926900ABE3BF /* PBXTextBookmark */; - 439B967D11E2926900ABE3BF /* PBXTextBookmark */ = 439B967D11E2926900ABE3BF /* PBXTextBookmark */; - 439B967E11E2926900ABE3BF /* PBXTextBookmark */ = 439B967E11E2926900ABE3BF /* PBXTextBookmark */; - 439B968211E292B400ABE3BF /* PBXTextBookmark */ = 439B968211E292B400ABE3BF /* PBXTextBookmark */; - 439B968411E292C700ABE3BF /* PBXTextBookmark */ = 439B968411E292C700ABE3BF /* PBXTextBookmark */; - 439B969411E2938F00ABE3BF /* PBXTextBookmark */ = 439B969411E2938F00ABE3BF /* PBXTextBookmark */; - 439B969911E293C500ABE3BF /* PBXTextBookmark */ = 439B969911E293C500ABE3BF /* PBXTextBookmark */; - 439B969E11E295CC00ABE3BF /* PBXTextBookmark */ = 439B969E11E295CC00ABE3BF /* PBXTextBookmark */; - 439B969F11E295CC00ABE3BF /* PBXTextBookmark */ = 439B969F11E295CC00ABE3BF /* PBXTextBookmark */; - 439B96A011E295CC00ABE3BF /* PBXTextBookmark */ = 439B96A011E295CC00ABE3BF /* PBXTextBookmark */; - 439B96A111E295CC00ABE3BF /* PBXTextBookmark */ = 439B96A111E295CC00ABE3BF /* PBXTextBookmark */; - 439B96A211E295CC00ABE3BF /* PBXTextBookmark */ = 439B96A211E295CC00ABE3BF /* PBXTextBookmark */; - 439B96A711E2981100ABE3BF /* PBXTextBookmark */ = 439B96A711E2981100ABE3BF /* PBXTextBookmark */; - 439B96A911E2981100ABE3BF /* PBXTextBookmark */ = 439B96A911E2981100ABE3BF /* PBXTextBookmark */; - 439B96AA11E2981100ABE3BF /* PBXTextBookmark */ = 439B96AA11E2981100ABE3BF /* PBXTextBookmark */; - 439B96AB11E2981100ABE3BF /* PBXTextBookmark */ = 439B96AB11E2981100ABE3BF /* PBXTextBookmark */; - 439B96AF11E2983100ABE3BF /* PBXTextBookmark */ = 439B96AF11E2983100ABE3BF /* PBXTextBookmark */; - 439B96B311E2984300ABE3BF /* PBXTextBookmark */ = 439B96B311E2984300ABE3BF /* PBXTextBookmark */; - 439B96B411E2984300ABE3BF /* PBXTextBookmark */ = 439B96B411E2984300ABE3BF /* PBXTextBookmark */; - 439B96B511E2984300ABE3BF /* PBXTextBookmark */ = 439B96B511E2984300ABE3BF /* PBXTextBookmark */; - 439B96B611E2985F00ABE3BF /* PBXTextBookmark */ = 439B96B611E2985F00ABE3BF /* PBXTextBookmark */; - 439B96B711E2985F00ABE3BF /* PBXTextBookmark */ = 439B96B711E2985F00ABE3BF /* PBXTextBookmark */; + 436A5FCD11E3F1C500622EE8 = 436A5FCD11E3F1C500622EE8 /* PBXTextBookmark */; + 436A5FD211E4128600622EE8 = 436A5FD211E4128600622EE8 /* PBXTextBookmark */; + 436A60AF11E510BD00622EE8 = 436A60AF11E510BD00622EE8 /* PBXTextBookmark */; + 439B966011E289A200ABE3BF = 439B966011E289A200ABE3BF /* PBXTextBookmark */; + 439B967B11E2926900ABE3BF = 439B967B11E2926900ABE3BF /* PBXTextBookmark */; + 439B969E11E295CC00ABE3BF = 439B969E11E295CC00ABE3BF /* PBXTextBookmark */; + 439B969F11E295CC00ABE3BF = 439B969F11E295CC00ABE3BF /* PBXTextBookmark */; + 439B96A011E295CC00ABE3BF = 439B96A011E295CC00ABE3BF /* PBXTextBookmark */; + 439B96A111E295CC00ABE3BF = 439B96A111E295CC00ABE3BF /* PBXTextBookmark */; + 439B96A711E2981100ABE3BF = 439B96A711E2981100ABE3BF /* PBXTextBookmark */; + 439B96C211E38CED00ABE3BF = 439B96C211E38CED00ABE3BF /* PBXTextBookmark */; + 439B96C411E38CED00ABE3BF = 439B96C411E38CED00ABE3BF /* PBXTextBookmark */; + 439B96C611E38CED00ABE3BF = 439B96C611E38CED00ABE3BF /* PBXTextBookmark */; + 439B975B11E3A4EC00ABE3BF = 439B975B11E3A4EC00ABE3BF /* PBXTextBookmark */; + 439B977211E3A79E00ABE3BF = 439B977211E3A79E00ABE3BF /* PBXTextBookmark */; + 439B977411E3A79E00ABE3BF = 439B977411E3A79E00ABE3BF /* PBXTextBookmark */; + 439B978611E3B2C500ABE3BF = 439B978611E3B2C500ABE3BF /* PBXTextBookmark */; + 439B97C011E3D52A00ABE3BF = 439B97C011E3D52A00ABE3BF /* PBXTextBookmark */; + 439B97CB11E3D94500ABE3BF = 439B97CB11E3D94500ABE3BF /* PBXTextBookmark */; 43A532B211DBD7B5004A1712 = 43A532B211DBD7B5004A1712 /* PBXTextBookmark */; 43A532B311DBD7B5004A1712 = 43A532B311DBD7B5004A1712 /* PBXTextBookmark */; 43A532B511DBD7B5004A1712 = 43A532B511DBD7B5004A1712 /* PBXTextBookmark */; @@ -148,40 +132,108 @@ 43A53D1F11DD221F004A1712 = 43A53D1F11DD221F004A1712 /* PBXTextBookmark */; 43A53D2011DD221F004A1712 = 43A53D2011DD221F004A1712 /* PBXTextBookmark */; 43A53D2111DD221F004A1712 = 43A53D2111DD221F004A1712 /* PBXTextBookmark */; - 43A53D2511DD221F004A1712 = 43A53D2511DD221F004A1712 /* PBXTextBookmark */; - 43A53D2711DD221F004A1712 = 43A53D2711DD221F004A1712 /* PBXTextBookmark */; 43A53D2E11DD221F004A1712 = 43A53D2E11DD221F004A1712 /* PBXTextBookmark */; - 43A53D8C11DD5018004A1712 = 43A53D8C11DD5018004A1712 /* PBXTextBookmark */; - 43A53D8D11DD5018004A1712 = 43A53D8D11DD5018004A1712 /* PBXTextBookmark */; 43B665DD11DD544700BDBA80 = 43B665DD11DD544700BDBA80 /* PBXTextBookmark */; - 43B665DE11DD544700BDBA80 = 43B665DE11DD544700BDBA80 /* PBXTextBookmark */; 43B665F711DD572D00BDBA80 = 43B665F711DD572D00BDBA80 /* PBXTextBookmark */; 43B665F811DD572D00BDBA80 = 43B665F811DD572D00BDBA80 /* PBXTextBookmark */; 43B665F911DD572D00BDBA80 = 43B665F911DD572D00BDBA80 /* PBXTextBookmark */; 43B665FA11DD572D00BDBA80 = 43B665FA11DD572D00BDBA80 /* PBXTextBookmark */; 43B665FB11DD572D00BDBA80 = 43B665FB11DD572D00BDBA80 /* PBXTextBookmark */; - 43B6660D11DD575600BDBA80 = 43B6660D11DD575600BDBA80 /* PBXTextBookmark */; - 43B6661511DD57AF00BDBA80 = 43B6661511DD57AF00BDBA80 /* PBXTextBookmark */; 43B6662611DD57D600BDBA80 = 43B6662611DD57D600BDBA80 /* PlistBookmark */; - 43B6662D11DD586F00BDBA80 = 43B6662D11DD586F00BDBA80 /* PBXTextBookmark */; 43B6663111DD591600BDBA80 = 43B6663111DD591600BDBA80 /* PBXTextBookmark */; - 43B6667111DE4AB700BDBA80 = 43B6667111DE4AB700BDBA80 /* PBXTextBookmark */; - 43C3FBA511DE844F002FA9FD = 43C3FBA511DE844F002FA9FD /* PBXTextBookmark */; 43C3FBA611DE844F002FA9FD = 43C3FBA611DE844F002FA9FD /* PBXTextBookmark */; - 43C3FBA711DE844F002FA9FD = 43C3FBA711DE844F002FA9FD /* PBXTextBookmark */; - 43C3FBA811DE844F002FA9FD = 43C3FBA811DE844F002FA9FD /* PBXTextBookmark */; - 43C3FBA911DE844F002FA9FD = 43C3FBA911DE844F002FA9FD /* PBXTextBookmark */; 43C7D65111D93C3E00E59A6F = 43C7D65111D93C3E00E59A6F /* PBXTextBookmark */; 43EF404B11D3FC5100B1F700 = 43EF404B11D3FC5100B1F700 /* PBXTextBookmark */; 43EF404D11D3FC5100B1F700 = 43EF404D11D3FC5100B1F700 /* PBXTextBookmark */; 43EF404F11D3FC5100B1F700 = 43EF404F11D3FC5100B1F700 /* PBXTextBookmark */; 43EF405111D3FC5100B1F700 = 43EF405111D3FC5100B1F700 /* PBXTextBookmark */; 43EF406211D3FF0200B1F700 = 43EF406211D3FF0200B1F700 /* PBXTextBookmark */; + 43FFF28D11E6CD9E00F9E529 = 43FFF28D11E6CD9E00F9E529 /* PBXTextBookmark */; + 43FFF28E11E6CD9E00F9E529 = 43FFF28E11E6CD9E00F9E529 /* PBXTextBookmark */; + 43FFF28F11E6CD9E00F9E529 = 43FFF28F11E6CD9E00F9E529 /* PBXTextBookmark */; + 43FFF29011E6CD9E00F9E529 = 43FFF29011E6CD9E00F9E529 /* PBXTextBookmark */; }; sourceControlManager = 4362EB3411B9937300E3DB3A /* Source Control */; userBuildSettings = { }; }; + 43150A8511E7862F008C6B68 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; + name = "SHKActionSheet.m: 73"; + rLen = 0; + rLoc = 2240; + rType = 0; + vrLen = 1375; + vrLoc = 1178; + }; + 43150A8611E7862F008C6B68 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; + name = "SHKActionSheet.m: 73"; + rLen = 0; + rLoc = 2240; + rType = 0; + vrLen = 1375; + vrLoc = 1178; + }; + 43150A8C11E78697008C6B68 /* SHKInstapaper.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 2210}}"; + sepNavSelRange = "{1539, 0}"; + sepNavVisRange = "{0, 1820}"; + }; + }; + 43150A9011E78702008C6B68 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; + name = "SHKActionSheet.m: 66"; + rLen = 0; + rLoc = 2074; + rType = 0; + vrLen = 1375; + vrLoc = 1178; + }; + 43150A9111E78702008C6B68 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43150A8C11E78697008C6B68 /* SHKInstapaper.m */; + name = "SHKInstapaper.m: 40"; + rLen = 0; + rLoc = 1539; + rType = 0; + vrLen = 1820; + vrLoc = 0; + }; + 43150A9211E78702008C6B68 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367611DBE3B9004A1712 /* SHKSharer.h */; + name = "SHKSharer.h: 104"; + rLen = 0; + rLoc = 2735; + rType = 0; + vrLen = 1224; + vrLoc = 1983; + }; + 43150A9311E78702008C6B68 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 296"; + rLen = 0; + rLoc = 6333; + rType = 0; + vrLen = 1235; + vrLoc = 5410; + }; + 43150A9D11E78722008C6B68 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; + name = "SHKSharer.m: 296"; + rLen = 0; + rLoc = 6333; + rType = 0; + vrLen = 1779; + vrLoc = 8652; + }; 4362EB2811B9936600E3DB3A /* ShareKit */ = { isa = PBXExecutable; activeArgIndices = ( @@ -238,122 +290,43 @@ vrLen = 322; vrLoc = 0; }; - 438D425B11C1A294001F8560 /* SHK.h */ = { - isa = PBXFileReference; - fileEncoding = 4; - lastKnownFileType = sourcecode.c.h; - name = SHK.h; - path = "/Users/nate/Documents/Development/ShareKit/Working Copy/Classes/ShareKit/Core/SHK.h"; - sourceTree = ""; - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 1573}}"; - sepNavSelRange = "{3326, 0}"; - sepNavVisRange = "{1958, 1369}"; - }; - }; - 439B963B11E288A300ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; - name = "SHKTwitter.m: 96"; - rLen = 0; - rLoc = 2786; - rType = 0; - vrLen = 898; - vrLoc = 2312; - }; - 439B963C11E288A300ABE3BF /* PBXTextBookmark */ = { + 436A5FCD11E3F1C500622EE8 /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 645"; + fRef = 438D425B11C1A294001F8560 /* SHK.h */; + name = "SHK.h: 120"; rLen = 0; - rLoc = 15511; + rLoc = 3326; rType = 0; - vrLen = 1609; - vrLoc = 14151; + vrLen = 1433; + vrLoc = 1894; }; - 439B963D11E288A300ABE3BF /* PBXTextBookmark */ = { + 436A5FD211E4128600622EE8 /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A5367611DBE3B9004A1712 /* SHKSharer.h */; - name = "SHKSharer.h: 104"; + fRef = 43A536A711DBE3B9004A1712 /* SHK.m */; + name = "SHK.m: 195"; rLen = 0; - rLoc = 2735; - rType = 0; - vrLen = 1203; - vrLoc = 2033; - }; - 439B963E11E288A300ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; - rLen = 23; - rLoc = 2176; - rType = 0; - }; - 439B963F11E288A300ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; - name = "SHKFacebook.m: 100"; - rLen = 23; - rLoc = 2176; + rLoc = 5283; rType = 0; - vrLen = 1224; - vrLoc = 3653; + vrLen = 1567; + vrLoc = 4611; }; - 439B965511E2892800ABE3BF /* PBXTextBookmark */ = { + 436A60AF11E510BD00622EE8 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 277"; - rLen = 0; - rLoc = 5810; - rType = 0; - vrLen = 1520; - vrLoc = 4770; - }; - 439B965611E2892800ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; - rLen = 0; - rLoc = 189; - rType = 1; - }; - 439B965711E2892800ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; - name = "SHKFacebook.m: 189"; - rLen = 0; - rLoc = 4404; + name = "SHKSharer.m: 283"; + rLen = 20; + rLoc = 5858; rType = 0; - vrLen = 1318; - vrLoc = 3552; + vrLen = 1316; + vrLoc = 5410; }; - 439B965D11E289A000ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; - name = "SHKFacebook.m: 187"; - rLen = 23; - rLoc = 4330; - rType = 0; - vrLen = 569; - vrLoc = 3945; - }; - 439B965E11E289A000ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; - name = "SHKFacebook.m: 187"; - rLen = 23; - rLoc = 4330; - rType = 0; - vrLen = 568; - vrLoc = 3945; - }; - 439B965F11E289A000ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; - name = "SHKFacebook.m: 187"; - rLen = 23; - rLoc = 4330; - rType = 0; - vrLen = 568; - vrLoc = 3945; + 438D425B11C1A294001F8560 /* SHK.h */ = { + isa = PBXFileReference; + fileEncoding = 4; + lastKnownFileType = sourcecode.c.h; + name = SHK.h; + path = "/Users/nate/Documents/Development/ShareKit/Working Copy/Classes/ShareKit/Core/SHK.h"; + sourceTree = ""; }; 439B966011E289A200ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; @@ -365,66 +338,6 @@ vrLen = 1318; vrLoc = 3552; }; - 439B966111E289A200ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; - name = "SHKTwitter.m: 96"; - rLen = 0; - rLoc = 2786; - rType = 0; - vrLen = 858; - vrLoc = 2312; - }; - 439B966211E289A200ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; - name = "SHKTwitter.m: 151"; - rLen = 0; - rLoc = 3992; - rType = 0; - vrLen = 1883; - vrLoc = 3039; - }; - 439B966611E2909300ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; - name = "SHKTwitter.m: 151"; - rLen = 0; - rLoc = 3992; - rType = 0; - vrLen = 1883; - vrLoc = 3039; - }; - 439B966711E2909300ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; - name = "SHKActivityIndicator.m: 150"; - rLen = 16; - rLoc = 4406; - rType = 0; - vrLen = 1058; - vrLoc = 3162; - }; - 439B966811E2909300ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; - name = "SHKCopy.m: 83"; - rLen = 0; - rLoc = 1923; - rType = 0; - vrLen = 770; - vrLoc = 1171; - }; - 439B966911E2909300ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; - name = "SHKCopy.m: 83"; - rLen = 0; - rLoc = 1948; - rType = 0; - vrLen = 795; - vrLoc = 1171; - }; 439B967B11E2926900ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; @@ -435,76 +348,6 @@ vrLen = 795; vrLoc = 1171; }; - 439B967C11E2926900ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 438D425B11C1A294001F8560 /* SHK.h */; - name = "SHK.h: 120"; - rLen = 0; - rLoc = 3326; - rType = 0; - vrLen = 1369; - vrLoc = 1958; - }; - 439B967D11E2926900ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; - name = "SHKActivityIndicator.m: 255"; - rLen = 0; - rLoc = 7650; - rType = 0; - vrLen = 1862; - vrLoc = 5314; - }; - 439B967E11E2926900ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; - name = "SHKActivityIndicator.m: 251"; - rLen = 0; - rLoc = 7581; - rType = 0; - vrLen = 1934; - vrLoc = 5256; - }; - 439B968211E292B400ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; - name = "SHKActivityIndicator.m: 248"; - rLen = 0; - rLoc = 7149; - rType = 0; - vrLen = 1754; - vrLoc = 5604; - }; - 439B968411E292C700ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; - name = "SHKActivityIndicator.m: 242"; - rLen = 0; - rLoc = 7022; - rType = 0; - vrLen = 1737; - vrLoc = 5604; - }; - 439B969411E2938F00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; - name = "SHKActivityIndicator.m: 83"; - rLen = 0; - rLoc = 2877; - rType = 0; - vrLen = 1828; - vrLoc = 1467; - }; - 439B969911E293C500ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; - name = "SHKActivityIndicator.m: 68"; - rLen = 0; - rLoc = 2548; - rType = 0; - vrLen = 1755; - vrLoc = 1412; - }; 439B969E11E295CC00ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */; @@ -545,16 +388,6 @@ vrLen = 1155; vrLoc = 2033; }; - 439B96A211E295CC00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 263"; - rLen = 0; - rLoc = 5428; - rType = 0; - vrLen = 1473; - vrLoc = 4817; - }; 439B96A711E2981100ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 439B96A811E2981100ABE3BF /* New Web Service.m */; @@ -567,117 +400,128 @@ }; 439B96A811E2981100ABE3BF /* New Web Service.m */ = { isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; name = "New Web Service.m"; path = "/Users/nate/Documents/Development/ShareKit/Working Copy/Template Src/ShareKit/New Web Service.m"; sourceTree = ""; }; - 439B96A911E2981100ABE3BF /* PBXTextBookmark */ = { + 439B96C211E38CED00ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 508"; + fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; + name = "SHKReadItLater.m: 119"; rLen = 0; - rLoc = 12068; + rLoc = 3213; rType = 0; - vrLen = 1702; - vrLoc = 10798; + vrLen = 1654; + vrLoc = 2694; }; - 439B96AA11E2981100ABE3BF /* PBXTextBookmark */ = { + 439B96C411E38CED00ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; - name = "SHKReadItLater.m: 135"; - rLen = 12; - rLoc = 3580; + fRef = 439B96C511E38CED00ABE3BF /* SHKConfig.h */; + name = "SHKConfig.h: 55"; + rLen = 0; + rLoc = 2215; rType = 0; - vrLen = 1499; - vrLoc = 2065; + vrLen = 2588; + vrLoc = 1175; + }; + 439B96C511E38CED00ABE3BF /* SHKConfig.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = SHKConfig.h; + path = /Users/nate/Downloads/0.1.1/Classes/ShareKit/SHKConfig.h; + sourceTree = ""; }; - 439B96AB11E2981100ABE3BF /* PBXTextBookmark */ = { + 439B96C611E38CED00ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; - name = "SHKReadItLater.m: 120"; - rLen = 0; - rLoc = 3213; + fRef = 439B96C711E38CED00ABE3BF /* SHKConfig.h */; + name = "SHKConfig.h: 56"; + rLen = 2622; + rLoc = 2241; rType = 0; - vrLen = 1387; - vrLoc = 2384; + vrLen = 2332; + vrLoc = 2533; }; - 439B96AF11E2983100ABE3BF /* PBXTextBookmark */ = { + 439B96C711E38CED00ABE3BF /* SHKConfig.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = SHKConfig.h; + path = /Users/nate/Documents/Development/ShareKit/Releases/0.1.0/Classes/ShareKit/SHKConfig.h; + sourceTree = ""; + }; + 439B96CD11E38CED00ABE3BF /* SHKConfig.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = SHKConfig.h; + path = /Users/nate/Downloads/0.1.2/Classes/ShareKit/SHKConfig.h; + sourceTree = ""; + }; + 439B975B11E3A4EC00ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; - name = "SHKReadItLater.m: 56"; + fRef = 439B96CD11E38CED00ABE3BF /* SHKConfig.h */; + name = "SHKConfig.h: 1"; rLen = 0; - rLoc = 1712; + rLoc = 0; rType = 0; - vrLen = 1439; - vrLoc = 627; + vrLen = 2410; + vrLoc = 0; }; - 439B96B111E2984200ABE3BF /* SHKSharer.m:417 */ = { - isa = PBXFileBreakpoint; - actions = ( - ); - breakpointStyle = 0; - continueAfterActions = 0; - countType = 0; - delayBeforeContinue = 0; - fileReference = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - functionName = "-show"; - hitCount = 1; - ignoreCount = 0; - lineNumber = 417; - location = ShareKit; - modificationTime = 300062788.685467; - originalNumberOfMultipleMatches = 1; - state = 1; - }; - 439B96B311E2984300ABE3BF /* PBXTextBookmark */ = { + 439B977211E3A79E00ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; - name = "SHKReadItLater.m: 56"; + fRef = 43A536EA11DBE3B9004A1712 /* SHKTwitterForm.h */; + name = "SHKTwitterForm.h: 1"; rLen = 0; - rLoc = 1712; + rLoc = 0; rType = 0; - vrLen = 1439; - vrLoc = 627; + vrLen = 1532; + vrLoc = 0; }; - 439B96B411E2984300ABE3BF /* PBXTextBookmark */ = { + 439B977411E3A79E00ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 508"; + fRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; + name = "SHKOAuthSharer.m: 99"; rLen = 0; - rLoc = 12068; + rLoc = 3069; rType = 0; - vrLen = 1552; - vrLoc = 8931; + vrLen = 1959; + vrLoc = 1915; }; - 439B96B511E2984300ABE3BF /* PBXTextBookmark */ = { + 439B978611E3B2C500ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 508"; - rLen = 0; - rLoc = 12068; + fRef = 43A536BC11DBE3B9004A1712 /* SHKMail.m */; + name = "SHKMail.m: 161"; + rLen = 27; + rLoc = 3983; rType = 0; - vrLen = 1554; - vrLoc = 8929; + vrLen = 1908; + vrLoc = 2669; }; - 439B96B611E2985F00ABE3BF /* PBXTextBookmark */ = { + 439B97C011E3D52A00ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 508"; + fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; + name = "SHKTwitter.m: 232"; rLen = 0; - rLoc = 12068; + rLoc = 6110; rType = 0; - vrLen = 1238; - vrLoc = 12353; + vrLen = 2008; + vrLoc = 5589; }; - 439B96B711E2985F00ABE3BF /* PBXTextBookmark */ = { + 439B97C311E3D52A00ABE3BF /* SHKConfig.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = SHKConfig.h; + path = /Users/nate/Documents/Development/ShareKit/Releases/0.1.2/Classes/ShareKit/SHKConfig.h; + sourceTree = ""; + }; + 439B97CB11E3D94500ABE3BF /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; - name = "SHKReadItLater.m: 119"; + fRef = 439B97C311E3D52A00ABE3BF /* SHKConfig.h */; + name = "SHKConfig.h: 50"; rLen = 0; - rLoc = 3213; + rLoc = 1920; rType = 0; - vrLen = 1654; - vrLoc = 2694; + vrLen = 2445; + vrLoc = 76; }; 43A532B211DBD7B5004A1712 /* PBXTextBookmark */ = { isa = PBXTextBookmark; @@ -732,9 +576,9 @@ }; 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1111, 3510}}"; - sepNavSelRange = "{6701, 0}"; - sepNavVisRange = "{6490, 1081}"; + sepNavIntBoundsRect = "{{0, 0}, {1034, 3653}}"; + sepNavSelRange = "{3069, 0}"; + sepNavVisRange = "{3064, 1136}"; sepNavWindowFrame = "{{67, 67}, {1047, 916}}"; }; }; @@ -742,14 +586,14 @@ uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {817, 2171}}"; sepNavSelRange = "{2735, 0}"; - sepNavVisRange = "{2033, 1155}"; + sepNavVisRange = "{1983, 1224}"; }; }; 43A5367711DBE3B9004A1712 /* SHKSharer.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1300, 8021}}"; - sepNavSelRange = "{12068, 0}"; - sepNavVisRange = "{12353, 1238}"; + sepNavIntBoundsRect = "{{0, 0}, {1300, 8502}}"; + sepNavSelRange = "{6333, 0}"; + sepNavVisRange = "{8652, 1779}"; sepNavWindowFrame = "{{-1163, 72}, {1047, 916}}"; }; }; @@ -789,11 +633,18 @@ sepNavWindowFrame = "{{203, 59}, {1047, 916}}"; }; }; + 43A536A611DBE3B9004A1712 /* SHK.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 1573}}"; + sepNavSelRange = "{3326, 0}"; + sepNavVisRange = "{1894, 1433}"; + }; + }; 43A536A711DBE3B9004A1712 /* SHK.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1219, 6318}}"; - sepNavSelRange = "{5365, 0}"; - sepNavVisRange = "{5268, 1011}"; + sepNavIntBoundsRect = "{{0, 0}, {1314, 6318}}"; + sepNavSelRange = "{5283, 0}"; + sepNavVisRange = "{4611, 1567}"; }; }; 43A536A811DBE3B9004A1712 /* SHKItem.h */ = { @@ -847,9 +698,9 @@ }; 43A536BC11DBE3B9004A1712 /* SHKMail.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1244, 2795}}"; - sepNavSelRange = "{3067, 25}"; - sepNavVisRange = "{2467, 1053}"; + sepNavIntBoundsRect = "{{0, 0}, {1244, 2405}}"; + sepNavSelRange = "{3983, 27}"; + sepNavVisRange = "{2669, 1908}"; }; }; 43A536C311DBE3B9004A1712 /* SHKDelicious.m */ = { @@ -862,9 +713,9 @@ }; 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {920, 2743}}"; - sepNavSelRange = "{4330, 23}"; - sepNavVisRange = "{3945, 568}"; + sepNavIntBoundsRect = "{{0, 0}, {920, 2574}}"; + sepNavSelRange = "{3728, 4}"; + sepNavVisRange = "{3356, 829}"; }; }; 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */ = { @@ -876,9 +727,9 @@ }; 43A536E311DBE3B9004A1712 /* SHKPinboard.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1279, 2015}}"; - sepNavSelRange = "{3614, 0}"; - sepNavVisRange = "{2847, 780}"; + sepNavIntBoundsRect = "{{0, 0}, {1279, 2197}}"; + sepNavSelRange = "{4355, 4}"; + sepNavVisRange = "{3988, 669}"; }; }; 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */ = { @@ -891,30 +742,38 @@ }; 43A536E911DBE3B9004A1712 /* SHKTwitter.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1734, 4940}}"; - sepNavSelRange = "{3992, 0}"; - sepNavVisRange = "{3039, 1883}"; + sepNavIntBoundsRect = "{{0, 0}, {1335, 5109}}"; + sepNavSelRange = "{6110, 0}"; + sepNavVisRange = "{5589, 2008}"; + }; + }; + 43A536EA11DBE3B9004A1712 /* SHKTwitterForm.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {784, 771}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1532}"; }; }; 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1174, 2574}}"; + sepNavIntBoundsRect = "{{0, 0}, {1174, 2548}}"; sepNavSelRange = "{3933, 0}"; - sepNavVisRange = "{3543, 1023}"; + sepNavVisRange = "{3543, 1074}"; }; }; 43A536EC11DBE3B9004A1712 /* SHKConfig.h */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1734, 1586}}"; - sepNavSelRange = "{3443, 0}"; - sepNavVisRange = "{1347, 2640}"; + sepNavIntBoundsRect = "{{0, 0}, {985, 1690}}"; + sepNavSelRange = "{1258, 0}"; + sepNavVisRange = "{0, 2590}"; + sepNavWindowFrame = "{{-1242, 82}, {1047, 916}}"; }; }; 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {929, 1079}}"; - sepNavSelRange = "{1097, 0}"; - sepNavVisRange = "{410, 1504}"; + sepNavIntBoundsRect = "{{0, 0}, {929, 1300}}"; + sepNavSelRange = "{2074, 0}"; + sepNavVisRange = "{1178, 1375}"; }; }; 43A536F011DBE3B9004A1712 /* SHKActivityIndicator.h */ = { @@ -939,6 +798,13 @@ sepNavWindowFrame = "{{-1196, 40}, {1047, 916}}"; }; }; + 43A536F311DBE3B9004A1712 /* SHKFormController.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {920, 3640}}"; + sepNavSelRange = "{2924, 4}"; + sepNavVisRange = "{2289, 933}"; + }; + }; 43A536F811DBE3B9004A1712 /* SHKNavController.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; @@ -962,9 +828,9 @@ }; 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {908, 4095}}"; - sepNavSelRange = "{235, 0}"; - sepNavVisRange = "{0, 530}"; + sepNavIntBoundsRect = "{{0, 0}, {957, 4212}}"; + sepNavSelRange = "{7565, 0}"; + sepNavVisRange = "{7119, 884}"; }; }; 43A5381D11DBE42D004A1712 /* PBXTextBookmark */ = { @@ -980,8 +846,8 @@ 43A5382F11DBE493004A1712 /* ExampleShareLink.m */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {1139, 1027}}"; - sepNavSelRange = "{2100, 0}"; - sepNavVisRange = "{1427, 1174}"; + sepNavSelRange = "{2101, 14}"; + sepNavVisRange = "{1346, 1257}"; }; }; 43A5383111DBE493004A1712 /* ExampleShareText.m */ = { @@ -1129,26 +995,6 @@ vrLen = 345; vrLoc = 0; }; - 43A53D2511DD221F004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; - name = "SHKCopy.m: 13"; - rLen = 748; - rLoc = 1218; - rType = 0; - vrLen = 772; - vrLoc = 74; - }; - 43A53D2711DD221F004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; - name = "SHKReadItLater.m: 116"; - rLen = 12; - rLoc = 3580; - rType = 0; - vrLen = 1710; - vrLoc = 1849; - }; 43A53D2E11DD221F004A1712 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43A536C311DBE3B9004A1712 /* SHKDelicious.m */; @@ -1159,26 +1005,6 @@ vrLen = 1443; vrLoc = 608; }; - 43A53D8C11DD5018004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5382F11DBE493004A1712 /* ExampleShareLink.m */; - name = "ExampleShareLink.m: 49"; - rLen = 0; - rLoc = 2469; - rType = 0; - vrLen = 1591; - vrLoc = 0; - }; - 43A53D8D11DD5018004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; - name = "SHKActionSheet.m: 50"; - rLen = 0; - rLoc = 2133; - rType = 0; - vrLen = 1504; - vrLoc = 410; - }; 43B665DD11DD544700BDBA80 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43A536A811DBE3B9004A1712 /* SHKItem.h */; @@ -1189,16 +1015,6 @@ vrLen = 1444; vrLoc = 74; }; - 43B665DE11DD544700BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367611DBE3B9004A1712 /* SHKSharer.h */; - name = "SHKSharer.h: 69"; - rLen = 0; - rLoc = 2504; - rType = 0; - vrLen = 1155; - vrLoc = 997; - }; 43B665F711DD572D00BDBA80 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43A5367E11DBE3B9004A1712 /* SFHFKeychainUtils.m */; @@ -1249,26 +1065,6 @@ vrLen = 1353; vrLoc = 0; }; - 43B6660D11DD575600BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 645"; - rLen = 0; - rLoc = 15511; - rType = 0; - vrLen = 1580; - vrLoc = 14180; - }; - 43B6661511DD57AF00BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 438D425B11C1A294001F8560 /* SHK.h */; - name = "SHK.h: 29"; - rLen = 0; - rLoc = 1197; - rType = 0; - vrLen = 1602; - vrLoc = 534; - }; 43B6662611DD57D600BDBA80 /* PlistBookmark */ = { isa = PlistBookmark; fRef = 43A536AC11DBE3B9004A1712 /* SHKSharers.plist */; @@ -1280,16 +1076,6 @@ rLen = 0; rLoc = 9223372036854775808; }; - 43B6662D11DD586F00BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536A711DBE3B9004A1712 /* SHK.m */; - name = "SHK.m: 209"; - rLen = 13; - rLoc = 5689; - rType = 0; - vrLen = 1427; - vrLoc = 5134; - }; 43B6663111DD591600BDBA80 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */; @@ -1300,26 +1086,6 @@ vrLen = 1486; vrLoc = 6873; }; - 43B6667111DE4AB700BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536BC11DBE3B9004A1712 /* SHKMail.m */; - name = "SHKMail.m: 131"; - rLen = 4; - rLoc = 3130; - rType = 0; - vrLen = 1660; - vrLoc = 2451; - }; - 43C3FBA511DE844F002FA9FD /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EC11DBE3B9004A1712 /* SHKConfig.h */; - name = "SHKConfig.h: 51"; - rLen = 0; - rLoc = 1953; - rType = 0; - vrLen = 2728; - vrLoc = 1258; - }; 43C3FBA611DE844F002FA9FD /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */; @@ -1330,36 +1096,6 @@ vrLen = 2469; vrLoc = 5669; }; - 43C3FBA711DE844F002FA9FD /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; - name = "SHKOAuthSharer.m: 205"; - rLen = 0; - rLoc = 6701; - rType = 0; - vrLen = 1703; - vrLoc = 6557; - }; - 43C3FBA811DE844F002FA9FD /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; - name = "SHKTwitter.m: 149"; - rLen = 64; - rLoc = 3913; - rType = 0; - vrLen = 1881; - vrLoc = 3346; - }; - 43C3FBA911DE844F002FA9FD /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; - name = "SHKTwitter.m: 149"; - rLen = 64; - rLoc = 3913; - rType = 0; - vrLen = 898; - vrLoc = 2312; - }; 43C7D65111D93C3E00E59A6F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 43C7D65211D93C3E00E59A6F /* OAMutableURLRequest.h */; @@ -1469,4 +1205,44 @@ vrLen = 1564; vrLoc = 1852; }; + 43FFF28D11E6CD9E00F9E529 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EC11DBE3B9004A1712 /* SHKConfig.h */; + name = "SHKConfig.h: 31"; + rLen = 0; + rLoc = 1258; + rType = 0; + vrLen = 2590; + vrLoc = 0; + }; + 43FFF28E11E6CD9E00F9E529 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A5382F11DBE493004A1712 /* ExampleShareLink.m */; + name = "ExampleShareLink.m: 59"; + rLen = 14; + rLoc = 2101; + rType = 0; + vrLen = 2071; + vrLoc = 548; + }; + 43FFF28F11E6CD9E00F9E529 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; + name = "SHKActionSheet.m: 45"; + rLen = 14; + rLoc = 1452; + rType = 0; + vrLen = 1375; + vrLoc = 1178; + }; + 43FFF29011E6CD9E00F9E529 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; + name = "SHKActionSheet.m: 45"; + rLen = 14; + rLoc = 1452; + rType = 0; + vrLen = 1375; + vrLoc = 1178; + }; } diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index e9ef771b..af874370 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -13,8 +13,8 @@ 2892E4100DC94CBA00A64D0F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */; }; 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD735F0D9D9599002E5188 /* MainWindow.xib */; }; 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28F335F01007B36200424DE2 /* RootViewController.xib */; }; - 3D384B5311E6AD2000C8056C /* SHKInstapaper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D384B5111E6AD2000C8056C /* SHKInstapaper.m */; }; 4312CF7C11CB33E200E61D7A /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4312CF7B11CB33E200E61D7A /* MessageUI.framework */; }; + 43150A8D11E78697008C6B68 /* SHKInstapaper.m in Sources */ = {isa = PBXBuildFile; fileRef = 43150A8C11E78697008C6B68 /* SHKInstapaper.m */; }; 43A5370011DBE3B9004A1712 /* SHKOAuthSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; }; 43A5370111DBE3B9004A1712 /* SHKSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; }; 43A5370211DBE3B9004A1712 /* UIWebView+SHK.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367A11DBE3B9004A1712 /* UIWebView+SHK.m */; }; @@ -99,6 +99,8 @@ 3D384B5111E6AD2000C8056C /* SHKInstapaper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SHKInstapaper.m; path = Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m; sourceTree = SOURCE_ROOT; }; 3D384B5211E6AD2000C8056C /* SHKInstapaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SHKInstapaper.h; path = Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h; sourceTree = SOURCE_ROOT; }; 4312CF7B11CB33E200E61D7A /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; + 43150A8B11E78697008C6B68 /* SHKInstapaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKInstapaper.h; sourceTree = ""; }; + 43150A8C11E78697008C6B68 /* SHKInstapaper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKInstapaper.m; sourceTree = ""; }; 43A5367411DBE3B9004A1712 /* SHKOAuthSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOAuthSharer.h; sourceTree = ""; }; 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOAuthSharer.m; sourceTree = ""; }; 43A5367611DBE3B9004A1712 /* SHKSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKSharer.h; sourceTree = ""; }; From 5a8c40d468d59861f6b66e1bfb358bec0bb56478 Mon Sep 17 00:00:00 2001 From: Jamie Pinkham Date: Sun, 11 Jul 2010 02:11:37 +0800 Subject: [PATCH 07/50] created tumblr sharer --- .gitignore | 3 + Classes/ShareKit/Core/SHKSharers.plist | 1 + Classes/ShareKit/SHKConfig.h | 6 +- .../Sharers/Services/Tumblr/SHKTumblr.h | 18 + .../Sharers/Services/Tumblr/SHKTumblr.m | 367 ++++++++++++++++++ ShareKit.xcodeproj/project.pbxproj | 18 +- 6 files changed, 406 insertions(+), 7 deletions(-) create mode 100644 .gitignore create mode 100644 Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.h create mode 100644 Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3bf3dee7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pbxuser +*.perspectivev3 +build diff --git a/Classes/ShareKit/Core/SHKSharers.plist b/Classes/ShareKit/Core/SHKSharers.plist index c50d11f0..5e742992 100644 --- a/Classes/ShareKit/Core/SHKSharers.plist +++ b/Classes/ShareKit/Core/SHKSharers.plist @@ -10,6 +10,7 @@ services + SHKTumblr SHKTwitter SHKPinboard SHKDelicious diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index f7058fe8..954f6c7a 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -26,14 +26,14 @@ // -#error Setup the SHKConfig.h file, then remove this error by commenting it out. +//#error Setup the SHKConfig.h file, then remove this error by commenting it out. // App Description // These values are used by any service that shows 'shared from XYZ' -#define SHKMyAppName @"My App Name" -#define SHKMyAppURL @"http://example.com" +#define SHKMyAppName @"Test Tumblr ShareKit App" +#define SHKMyAppURL @"http://jamiepinkham.com" diff --git a/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.h b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.h new file mode 100644 index 00000000..3ba93c4b --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.h @@ -0,0 +1,18 @@ +// +// SHKTumblr.h +// ShareKit +// +// Created by Jamie Pinkham on 7/10/10. +// Copyright 2010 Mobelux. All rights reserved. +// + +#import +#import "SHKSharer.h" + +@interface SHKTumblr : SHKSharer { + //for photo posts + NSMutableData *data; + NSHTTPURLResponse *response; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m new file mode 100644 index 00000000..ece8c120 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m @@ -0,0 +1,367 @@ +// +// SHKTumblr.m +// ShareKit +// +// Created by Jamie Pinkham on 7/10/10. +// Copyright 2010 Mobelux. All rights reserved. +// + +#import "SHKTumblr.h" + +static NSString * const kTumblrAuthenticationURL = @"https://www.tumblr.com/api/authenticate"; +static NSString * const kTumblrWriteURL = @"https://www.tumblr.com/api/write"; + +@interface SHKTumblr() +- (void)finish; +@end + +@implementation SHKTumblr + +#pragma mark - +#pragma mark Memory management +- (void)dealloc{ + [data release]; + [response release]; + [super dealloc]; +} + +#pragma mark - +#pragma mark Configuration : Service Defination + ++ (NSString *)sharerTitle{ + return @"Tumblr"; +} + ++ (BOOL)canShareURL{ + return YES; +} + ++ (BOOL)canShareText{ + return YES; +} + ++ (BOOL)canShareImage{ + return YES; +} + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + ++ (BOOL)canShare{ + return YES; +} + +- (BOOL)shouldAutoShare{ + return NO; +} + +#pragma mark - +#pragma mark Authorization + +- (NSString *)authorizationFormCaption{ + return @"Set up a free account at http://tumblr.com"; +} + +- (void)authorizationFormValidate:(SHKFormController *)form{ + // Display an activity indicator + if (!quiet) + [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + + + // Authorize the user through the server + NSDictionary *formValues = [form formValues]; + + NSString *params = [NSMutableString stringWithFormat:@"email=%@&password=%@", + SHKEncode([formValues objectForKey:@"email"]), + SHKEncode([formValues objectForKey:@"password"]) + ]; + + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:kTumblrAuthenticationURL] + params:params + delegate:self + isFinishedSelector:@selector(authFinished:) + method:@"POST" + autostart:YES] autorelease]; + + self.pendingForm = form; +} + +- (void)authFinished:(SHKRequest *)aRequest{ + [[SHKActivityIndicator currentIndicator] hide]; + if (aRequest.success) + [pendingForm saveForm]; + + else { + NSString *errorMessage = nil; + if (aRequest.response.statusCode == 403) + errorMessage = @"Invalid email or password."; + else + errorMessage = @"The service encountered an error. Please try again later."; + + [[[[UIAlertView alloc] initWithTitle:@"Login Error" + message:errorMessage + delegate:nil + cancelButtonTitle:@"Close" + otherButtonTitles:nil] autorelease] show]; + } +} + +#pragma mark - +#pragma mark Authorize form +- (NSArray *)authorizationFormFields{ + return [NSArray arrayWithObjects: + [SHKFormFieldSettings label:@"Email" + key:@"email" + type:SHKFormFieldTypeText + start:nil], + [SHKFormFieldSettings label:@"Password" + key:@"password" + type:SHKFormFieldTypePassword + start:nil], + nil]; +} + +#pragma mark - +#pragma mark Share Form + +- (NSArray *)shareFormFieldsForType:(SHKShareType)type{ + NSMutableArray *baseArray = [NSMutableArray arrayWithObjects: + [SHKFormFieldSettings label:@"Tags" + key:@"tags" + type:SHKFormFieldTypeText + start:item.tags], + [SHKFormFieldSettings label:@"Slug" + key:@"slug" + type:SHKFormFieldTypeText + start:nil], + [SHKFormFieldSettings label:@"Private" + key:@"private" + type:SHKFormFieldTypeSwitch + start:SHKFormFieldSwitchOff], + [SHKFormFieldSettings label:@"Send to Twitter" + key:@"twitter" + type:SHKFormFieldTypeSwitch + start:SHKFormFieldSwitchOff], + nil + ]; + if([item shareType] == SHKShareTypeImage){ + [baseArray insertObject:[SHKFormFieldSettings label:@"Caption" + key:@"caption" + type:SHKFormFieldTypeText + start:nil] + atIndex:0]; + }else{ + [baseArray insertObject:[SHKFormFieldSettings label:@"Title" + key:@"title" + type:SHKFormFieldTypeText + start:item.title] + atIndex:0]; + } + return baseArray; +} + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send{ + if ([self validateItem]) { + if([item shareType] == SHKShareTypeText || [item shareType] == SHKShareTypeURL){ + NSMutableString *params = [NSMutableString stringWithFormat:@"email=%@&password=%@", + SHKEncode([self getAuthValueForKey:@"email"]), + SHKEncode([self getAuthValueForKey:@"password"])]; + + //set send to twitter param + if([item customBoolForSwitchKey:@"twitter"]){ + [params appendFormat:@"&send-to-twitter=auto"]; + }else{ + [params appendFormat:@"&send-to-twitter=no"]; + } + + //set tags param + NSString *tags = [item tags]; + if(tags){ + [params appendFormat:@"&tags=%@",[item tags]]; + } + + //set slug param + NSString *slug = [item customValueForKey:@"slug"]; + if(slug){ + [params appendFormat:@"&slug=%@", slug]; + } + + //set private param + if([item customBoolForSwitchKey:@"private"]){ + [params appendFormat:@"&private=1"]; + }else{ + [params appendFormat:@"&private=0"]; + } + + //set type param + if ([item shareType] == SHKShareTypeURL){ + [params appendString:@"&type=link"]; + [params appendFormat:@"&url=%@",SHKEncodeURL([item URL])]; + if([item title]){ + [params appendFormat:@"&name=%@", SHKEncode([item title])]; + } + }else{ + [params appendString:@"&type=regular"]; + if([item title]){ + [params appendFormat:@"&title=%@", SHKEncode([item title])]; + } + [params appendFormat:@"&body=%@", SHKEncode([item text])]; + } + self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:kTumblrWriteURL] + params:params + delegate:self + isFinishedSelector:@selector(sendFinished:) + method:@"POST" + autostart:YES] autorelease]; + } + else if([item shareType] == SHKShareTypeImage){ + + NSData *imageData = UIImageJPEGRepresentation([item image], 90); + NSMutableURLRequest *aRequest = [[[NSMutableURLRequest alloc] init] autorelease]; + [aRequest setURL:[NSURL URLWithString:kTumblrWriteURL]]; + [aRequest setHTTPMethod:@"POST"]; + NSString *boundary = @"0xKhTmLbOuNdArY"; + //NSString *boundary = [NSString stringWithString:@"---------------------------14737809831466499882746641449"]; + NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary]; + [aRequest addValue:contentType forHTTPHeaderField: @"Content-Type"]; + + /* + now lets create the body of the post + */ + NSMutableData *body = [NSMutableData data]; + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Disposition: form-data; name=\"email\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[[self getAuthValueForKey:@"email"] dataUsingEncoding:NSUTF8StringEncoding]]; + + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Disposition: form-data; name=\"password\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[[self getAuthValueForKey:@"password"] dataUsingEncoding:NSUTF8StringEncoding]]; + + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Disposition: form-data; name=\"type\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"photo" dataUsingEncoding:NSUTF8StringEncoding]]; + + if([item tags]){ + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Disposition: form-data; name=\"tags\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[[item tags] dataUsingEncoding:NSUTF8StringEncoding]]; + } + if([item customValueForKey:@"caption"]){ + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Disposition: form-data; name=\"caption\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[[item customValueForKey:@"caption"] dataUsingEncoding:NSUTF8StringEncoding]]; + + } + if([item customValueForKey:@"slug"]){ + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Disposition: form-data; name=\"slug\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[[item customValueForKey:@"slug"] dataUsingEncoding:NSUTF8StringEncoding]]; + } + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + if([item customBoolForSwitchKey:@"private"]){ + [body appendData:[@"Content-Disposition: form-data; name=\"private\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"1" dataUsingEncoding:NSUTF8StringEncoding]]; + }else{ + [body appendData:[@"Content-Disposition: form-data; name=\"private\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"0" dataUsingEncoding:NSUTF8StringEncoding]]; + } + + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] + dataUsingEncoding:NSUTF8StringEncoding]]; + if([item customBoolForSwitchKey:@"twitter"]){ + [body appendData:[@"Content-Disposition: form-data; name=\"twitter\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"auto" dataUsingEncoding:NSUTF8StringEncoding]]; + }else{ + [body appendData:[@"Content-Disposition: form-data; name=\"twitter\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"no" dataUsingEncoding:NSUTF8StringEncoding]]; + } + + [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Disposition: form-data; name=\"data\"; filename=\"upload.jpg\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Transfer-Encoding: image/jpg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:imageData]; + [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + + // setting the body of the post to the reqeust + [aRequest setHTTPBody:body]; + [NSURLConnection connectionWithRequest:aRequest delegate:self]; + } + + + // Notify delegate + [self sendDidStart]; + + return YES; + } + + return NO; +} + +- (void)sendFinished:(SHKRequest *)aRequest{ + if (!aRequest.success) { + if (aRequest.response.statusCode == 403) { + [self sendDidFailWithError:[SHK error:@"Invalid email or password."] shouldRelogin:YES]; + return; + } + else if (aRequest.response.statusCode == 500) { + [self sendDidFailWithError:[SHK error:@"The service encountered an error. Please try again later."]]; + return; + } + + [self sendDidFailWithError:[SHK error:@"There was a sending your post to Tumblr."]]; + return; + } + + [self sendDidFinish]; +} + +#pragma mark - +#pragma mark NSURLConnection delegate methods for image posts +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)theResponse { + [response release]; + response = [theResponse retain]; + + [data setLength:0]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d { + [data appendData:d]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + [self finish]; +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + + [self finish]; +} + +- (void)finish{ + if(response.statusCode == 200 || response.statusCode == 201){ + [self sendDidFinish]; + }else{ + if(response.statusCode == 403) { + [self sendDidFailWithError:[SHK error:@"Invalid email or password."] shouldRelogin:YES]; + return; + } + else if (response.statusCode == 500) { + [self sendDidFailWithError:[SHK error:@"The service encountered an error. Please try again later."]]; + return; + } + [self sendDidFailWithError:[SHK error:@"There was a sending your post to Tumblr."]]; + } + +} + +@end diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index af874370..e2f166ab 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD735F0D9D9599002E5188 /* MainWindow.xib */; }; 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28F335F01007B36200424DE2 /* RootViewController.xib */; }; 4312CF7C11CB33E200E61D7A /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4312CF7B11CB33E200E61D7A /* MessageUI.framework */; }; - 43150A8D11E78697008C6B68 /* SHKInstapaper.m in Sources */ = {isa = PBXBuildFile; fileRef = 43150A8C11E78697008C6B68 /* SHKInstapaper.m */; }; 43A5370011DBE3B9004A1712 /* SHKOAuthSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; }; 43A5370111DBE3B9004A1712 /* SHKSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; }; 43A5370211DBE3B9004A1712 /* UIWebView+SHK.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367A11DBE3B9004A1712 /* UIWebView+SHK.m */; }; @@ -85,6 +84,7 @@ 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */; }; 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; 43EF406E11D3FFF800B1F700 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43EF406D11D3FFF800B1F700 /* Security.framework */; }; + E88E853711E8C4C90089EB8B /* SHKTumblr.m in Sources */ = {isa = PBXBuildFile; fileRef = E88E853611E8C4C90089EB8B /* SHKTumblr.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -99,8 +99,6 @@ 3D384B5111E6AD2000C8056C /* SHKInstapaper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SHKInstapaper.m; path = Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m; sourceTree = SOURCE_ROOT; }; 3D384B5211E6AD2000C8056C /* SHKInstapaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SHKInstapaper.h; path = Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h; sourceTree = SOURCE_ROOT; }; 4312CF7B11CB33E200E61D7A /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; - 43150A8B11E78697008C6B68 /* SHKInstapaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKInstapaper.h; sourceTree = ""; }; - 43150A8C11E78697008C6B68 /* SHKInstapaper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKInstapaper.m; sourceTree = ""; }; 43A5367411DBE3B9004A1712 /* SHKOAuthSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOAuthSharer.h; sourceTree = ""; }; 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOAuthSharer.m; sourceTree = ""; }; 43A5367611DBE3B9004A1712 /* SHKSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKSharer.h; sourceTree = ""; }; @@ -240,6 +238,8 @@ 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 43EF406D11D3FFF800B1F700 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 8D1107310486CEB800E47090 /* ShareKit-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ShareKit-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; + E88E853511E8C4C90089EB8B /* SHKTumblr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKTumblr.h; sourceTree = ""; }; + E88E853611E8C4C90089EB8B /* SHKTumblr.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTumblr.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -544,6 +544,7 @@ 43A536C011DBE3B9004A1712 /* Services */ = { isa = PBXGroup; children = ( + E88E853411E8C4B00089EB8B /* Tumblr */, 43A536C111DBE3B9004A1712 /* Delicious */, 43A536C411DBE3B9004A1712 /* Facebook */, 43A536DE11DBE3B9004A1712 /* Google Reader */, @@ -688,6 +689,15 @@ name = Form; sourceTree = ""; }; + E88E853411E8C4B00089EB8B /* Tumblr */ = { + isa = PBXGroup; + children = ( + E88E853511E8C4C90089EB8B /* SHKTumblr.h */, + E88E853611E8C4C90089EB8B /* SHKTumblr.m */, + ); + path = Tumblr; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -818,7 +828,7 @@ 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */, 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */, 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */, - 3D384B5311E6AD2000C8056C /* SHKInstapaper.m in Sources */, + E88E853711E8C4C90089EB8B /* SHKTumblr.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From fc9d54eb9cf6ec5128a44fb806f832b475add526 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Mon, 12 Jul 2010 13:05:45 -0700 Subject: [PATCH 08/50] reverting changes from SHKConfig made by fork --- Classes/ShareKit/SHKConfig.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 954f6c7a..f7058fe8 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -26,14 +26,14 @@ // -//#error Setup the SHKConfig.h file, then remove this error by commenting it out. +#error Setup the SHKConfig.h file, then remove this error by commenting it out. // App Description // These values are used by any service that shows 'shared from XYZ' -#define SHKMyAppName @"Test Tumblr ShareKit App" -#define SHKMyAppURL @"http://jamiepinkham.com" +#define SHKMyAppName @"My App Name" +#define SHKMyAppURL @"http://example.com" From dcb84c374d3f5bbcfb65be45f8e89b9b27de005f Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Mon, 12 Jul 2010 13:22:07 -0700 Subject: [PATCH 09/50] removing user pbx files from example project --- ShareKit.xcodeproj/nate.mode1v3 | 1471 ------------------------------- ShareKit.xcodeproj/nate.pbxuser | 1248 -------------------------- 2 files changed, 2719 deletions(-) delete mode 100644 ShareKit.xcodeproj/nate.mode1v3 delete mode 100644 ShareKit.xcodeproj/nate.pbxuser diff --git a/ShareKit.xcodeproj/nate.mode1v3 b/ShareKit.xcodeproj/nate.mode1v3 deleted file mode 100644 index bbd2724a..00000000 --- a/ShareKit.xcodeproj/nate.mode1v3 +++ /dev/null @@ -1,1471 +0,0 @@ - - - - - ActivePerspectiveName - Project - AllowedModules - - - BundleLoadPath - - MaxInstances - n - Module - PBXSmartGroupTreeModule - Name - Groups and Files Outline View - - - BundleLoadPath - - MaxInstances - n - Module - PBXNavigatorGroup - Name - Editor - - - BundleLoadPath - - MaxInstances - n - Module - XCTaskListModule - Name - Task List - - - BundleLoadPath - - MaxInstances - n - Module - XCDetailModule - Name - File and Smart Group Detail Viewer - - - BundleLoadPath - - MaxInstances - 1 - Module - PBXBuildResultsModule - Name - Detailed Build Results Viewer - - - BundleLoadPath - - MaxInstances - 1 - Module - PBXProjectFindModule - Name - Project Batch Find Tool - - - BundleLoadPath - - MaxInstances - n - Module - XCProjectFormatConflictsModule - Name - Project Format Conflicts List - - - BundleLoadPath - - MaxInstances - n - Module - PBXBookmarksModule - Name - Bookmarks Tool - - - BundleLoadPath - - MaxInstances - n - Module - PBXClassBrowserModule - Name - Class Browser - - - BundleLoadPath - - MaxInstances - n - Module - PBXCVSModule - Name - Source Code Control Tool - - - BundleLoadPath - - MaxInstances - n - Module - PBXDebugBreakpointsModule - Name - Debug Breakpoints Tool - - - BundleLoadPath - - MaxInstances - n - Module - XCDockableInspector - Name - Inspector - - - BundleLoadPath - - MaxInstances - n - Module - PBXOpenQuicklyModule - Name - Open Quickly Tool - - - BundleLoadPath - - MaxInstances - 1 - Module - PBXDebugSessionModule - Name - Debugger - - - BundleLoadPath - - MaxInstances - 1 - Module - PBXDebugCLIModule - Name - Debug Console - - - BundleLoadPath - - MaxInstances - n - Module - XCSnapshotModule - Name - Snapshots Tool - - - BundlePath - /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources - Description - DefaultDescriptionKey - DockingSystemVisible - - Extension - mode1v3 - FavBarConfig - - PBXProjectModuleGUID - 4362EB7611B9A14600E3DB3A - XCBarModuleItemNames - - XCBarModuleItems - - - FirstTimeWindowDisplayed - - Identifier - com.apple.perspectives.project.mode1v3 - MajorVersion - 33 - MinorVersion - 0 - Name - Default - Notifications - - OpenEditors - - PerspectiveWidths - - -1 - -1 - - Perspectives - - - ChosenToolbarItems - - active-combo-popup - action - NSToolbarFlexibleSpaceItem - debugger-enable-breakpoints - go - buildOrClean - build-and-go - com.apple.ide.PBXToolbarStopButton - NSToolbarFlexibleSpaceItem - servicesModuledebug - com.apple.ide.organizer - NSToolbarFlexibleSpaceItem - com.apple.pbx.toolbar.searchfield - - ControllerClassBaseName - - IconName - WindowOfProjectWithEditor - Identifier - perspective.project - IsVertical - - Layout - - - ContentConfiguration - - PBXBottomSmartGroupGIDs - - 1C37FBAC04509CD000000102 - 1C37FAAC04509CD000000102 - 1C37FABC05509CD000000102 - 1C37FABC05539CD112110102 - E2644B35053B69B200211256 - 1C37FABC04509CD000100104 - 1CC0EA4004350EF90044410B - 1CC0EA4004350EF90041110B - - PBXProjectModuleGUID - 1CE0B1FE06471DED0097A5F4 - PBXProjectModuleLabel - Files - PBXProjectStructureProvided - yes - PBXSmartGroupTreeModuleColumnData - - PBXSmartGroupTreeModuleColumnWidthsKey - - 316 - - PBXSmartGroupTreeModuleColumnsKey_v4 - - MainColumn - - - PBXSmartGroupTreeModuleOutlineStateKey_v7 - - PBXSmartGroupTreeModuleOutlineStateExpansionKey - - 29B97314FDCFA39411CA2CEA - 080E96DDFE201D6D7F000001 - 43A5367111DBE3B9004A1712 - 43A536AD11DBE3B9004A1712 - 43A5367211DBE3B9004A1712 - 43A5367311DBE3B9004A1712 - 43A5367B11DBE3B9004A1712 - 43A536B511DBE3B9004A1712 - 43A536B611DBE3B9004A1712 - 43A536B711DBE3B9004A1712 - 43A536BA11DBE3B9004A1712 - 43A536C011DBE3B9004A1712 - 43A536C411DBE3B9004A1712 - 43A536DE11DBE3B9004A1712 - 43150A8A11E78697008C6B68 - 43A536E411DBE3B9004A1712 - 43A536E711DBE3B9004A1712 - 43A536ED11DBE3B9004A1712 - 4362EB3311B9937300E3DB3A - 29B97315FDCFA39411CA2CEA - 29B97317FDCFA39411CA2CEA - 29B97323FDCFA39411CA2CEA - - PBXSmartGroupTreeModuleOutlineStateSelectionKey - - - 19 - 15 - 7 - 2 - 1 - 0 - - - PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 250}, {316, 813}} - - PBXTopSmartGroupGIDs - - XCIncludePerspectivesSwitch - - XCSharingToken - com.apple.Xcode.GFSharingToken - - GeometryConfiguration - - Frame - {{0, 0}, {333, 831}} - GroupTreeTableConfiguration - - MainColumn - 316 - - RubberWindowFrame - 59 110 1183 872 0 0 1280 1002 - - Module - PBXSmartGroupTreeModule - Proportion - 333pt - - - Dock - - - BecomeActive - - ContentConfiguration - - PBXProjectModuleGUID - 1CE0B20306471E060097A5F4 - PBXProjectModuleLabel - SHKSharer.m - PBXSplitModuleInNavigatorKey - - Split0 - - PBXProjectModuleGUID - 1CE0B20406471E060097A5F4 - PBXProjectModuleLabel - SHKSharer.m - _historyCapacity - 0 - bookmark - 43150A9D11E78722008C6B68 - history - - 4362EB6D11B9A14600E3DB3A - 43EF404B11D3FC5100B1F700 - 43EF404D11D3FC5100B1F700 - 43EF404F11D3FC5100B1F700 - 43EF405111D3FC5100B1F700 - 43EF406211D3FF0200B1F700 - 43C7D65111D93C3E00E59A6F - 43A532B211DBD7B5004A1712 - 43A532B311DBD7B5004A1712 - 43A532B511DBD7B5004A1712 - 43A5381D11DBE42D004A1712 - 43A53C6711DC0AF8004A1712 - 43A53C6811DC0AF8004A1712 - 43A53C6911DC0AF8004A1712 - 43A53C6C11DC0AF8004A1712 - 43A53C6D11DC0AF8004A1712 - 43A53C6F11DC0AF8004A1712 - 43A53D1D11DD221F004A1712 - 43A53D1E11DD221F004A1712 - 43A53D1F11DD221F004A1712 - 43A53D2011DD221F004A1712 - 43A53D2111DD221F004A1712 - 43A53D2E11DD221F004A1712 - 43B665DD11DD544700BDBA80 - 43B665F711DD572D00BDBA80 - 43B665F811DD572D00BDBA80 - 43B665F911DD572D00BDBA80 - 43B665FA11DD572D00BDBA80 - 43B665FB11DD572D00BDBA80 - 43B6662611DD57D600BDBA80 - 43B6663111DD591600BDBA80 - 43C3FBA611DE844F002FA9FD - 439B966011E289A200ABE3BF - 439B967B11E2926900ABE3BF - 439B969E11E295CC00ABE3BF - 439B969F11E295CC00ABE3BF - 439B96A011E295CC00ABE3BF - 439B96A711E2981100ABE3BF - 439B96C211E38CED00ABE3BF - 439B96C411E38CED00ABE3BF - 439B96C611E38CED00ABE3BF - 439B975B11E3A4EC00ABE3BF - 439B977211E3A79E00ABE3BF - 439B977411E3A79E00ABE3BF - 439B978611E3B2C500ABE3BF - 439B97C011E3D52A00ABE3BF - 439B97CB11E3D94500ABE3BF - 436A5FCD11E3F1C500622EE8 - 436A5FD211E4128600622EE8 - 43FFF28D11E6CD9E00F9E529 - 43FFF28E11E6CD9E00F9E529 - 43150A9011E78702008C6B68 - 43150A9111E78702008C6B68 - 43150A9211E78702008C6B68 - 436A60AF11E510BD00622EE8 - - - SplitCount - 1 - - StatusBarVisibility - - - GeometryConfiguration - - Frame - {{0, 0}, {845, 826}} - RubberWindowFrame - 59 110 1183 872 0 0 1280 1002 - - Module - PBXNavigatorGroup - Proportion - 826pt - - - ContentConfiguration - - PBXProjectModuleGUID - 1CE0B20506471E060097A5F4 - PBXProjectModuleLabel - Detail - - GeometryConfiguration - - Frame - {{0, 831}, {845, 0}} - RubberWindowFrame - 59 110 1183 872 0 0 1280 1002 - - Module - XCDetailModule - Proportion - 0pt - - - Proportion - 845pt - - - Name - Project - ServiceClasses - - XCModuleDock - PBXSmartGroupTreeModule - XCModuleDock - PBXNavigatorGroup - XCDetailModule - - TableOfContents - - 43150A8711E7862F008C6B68 - 1CE0B1FE06471DED0097A5F4 - 43150A8811E7862F008C6B68 - 1CE0B20306471E060097A5F4 - 1CE0B20506471E060097A5F4 - - ToolbarConfigUserDefaultsMinorVersion - 2 - ToolbarConfiguration - xcode.toolbar.config.defaultV3 - - - ControllerClassBaseName - - IconName - WindowOfProject - Identifier - perspective.morph - IsVertical - 0 - Layout - - - BecomeActive - 1 - ContentConfiguration - - PBXBottomSmartGroupGIDs - - 1C37FBAC04509CD000000102 - 1C37FAAC04509CD000000102 - 1C08E77C0454961000C914BD - 1C37FABC05509CD000000102 - 1C37FABC05539CD112110102 - E2644B35053B69B200211256 - 1C37FABC04509CD000100104 - 1CC0EA4004350EF90044410B - 1CC0EA4004350EF90041110B - - PBXProjectModuleGUID - 11E0B1FE06471DED0097A5F4 - PBXProjectModuleLabel - Files - PBXProjectStructureProvided - yes - PBXSmartGroupTreeModuleColumnData - - PBXSmartGroupTreeModuleColumnWidthsKey - - 186 - - PBXSmartGroupTreeModuleColumnsKey_v4 - - MainColumn - - - PBXSmartGroupTreeModuleOutlineStateKey_v7 - - PBXSmartGroupTreeModuleOutlineStateExpansionKey - - 29B97314FDCFA39411CA2CEA - 1C37FABC05509CD000000102 - - PBXSmartGroupTreeModuleOutlineStateSelectionKey - - - 0 - - - PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 0}, {186, 337}} - - PBXTopSmartGroupGIDs - - XCIncludePerspectivesSwitch - 1 - XCSharingToken - com.apple.Xcode.GFSharingToken - - GeometryConfiguration - - Frame - {{0, 0}, {203, 355}} - GroupTreeTableConfiguration - - MainColumn - 186 - - RubberWindowFrame - 373 269 690 397 0 0 1440 878 - - Module - PBXSmartGroupTreeModule - Proportion - 100% - - - Name - Morph - PreferredWidth - 300 - ServiceClasses - - XCModuleDock - PBXSmartGroupTreeModule - - TableOfContents - - 11E0B1FE06471DED0097A5F4 - - ToolbarConfiguration - xcode.toolbar.config.default.shortV3 - - - PerspectivesBarVisible - - ShelfIsVisible - - SourceDescription - file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' - StatusbarIsVisible - - TimeStamp - 0.0 - ToolbarConfigUserDefaultsMinorVersion - 2 - ToolbarDisplayMode - 1 - ToolbarIsVisible - - ToolbarSizeMode - 1 - Type - Perspectives - UpdateMessage - The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? - WindowJustification - 5 - WindowOrderList - - 43150A9E11E78722008C6B68 - 43150A9B11E78702008C6B68 - 43150A9C11E78702008C6B68 - 1C78EAAD065D492600B07095 - 1CD10A99069EF8BA00B06720 - 4362EB7711B9A14600E3DB3A - /Users/nate/Documents/Development/ShareKit/Working Copy/ShareKit.xcodeproj - - WindowString - 59 110 1183 872 0 0 1280 1002 - WindowToolsV3 - - - FirstTimeWindowDisplayed - - Identifier - windowTool.build - IsVertical - - Layout - - - Dock - - - ContentConfiguration - - PBXProjectModuleGUID - 1CD0528F0623707200166675 - PBXProjectModuleLabel - - StatusBarVisibility - - - GeometryConfiguration - - Frame - {{0, 0}, {953, 445}} - RubberWindowFrame - -1136 159 953 825 -1280 0 1280 1024 - - Module - PBXNavigatorGroup - Proportion - 445pt - - - ContentConfiguration - - PBXProjectModuleGUID - XCMainBuildResultsModuleGUID - PBXProjectModuleLabel - Build Results - XCBuildResultsTrigger_Collapse - 1021 - XCBuildResultsTrigger_Open - 1011 - - GeometryConfiguration - - Frame - {{0, 450}, {953, 334}} - RubberWindowFrame - -1136 159 953 825 -1280 0 1280 1024 - - Module - PBXBuildResultsModule - Proportion - 334pt - - - Proportion - 784pt - - - Name - Build Results - ServiceClasses - - PBXBuildResultsModule - - StatusbarIsVisible - - TableOfContents - - 4362EB7711B9A14600E3DB3A - 43150A8911E7862F008C6B68 - 1CD0528F0623707200166675 - XCMainBuildResultsModuleGUID - - ToolbarConfiguration - xcode.toolbar.config.buildV3 - WindowContentMinSize - 486 300 - WindowString - -1136 159 953 825 -1280 0 1280 1024 - WindowToolGUID - 4362EB7711B9A14600E3DB3A - WindowToolIsVisible - - - - FirstTimeWindowDisplayed - - Identifier - windowTool.debugger - IsVertical - - Layout - - - Dock - - - ContentConfiguration - - Debugger - - HorizontalSplitView - - _collapsingFrameDimension - 0.0 - _indexOfCollapsedView - 0 - _percentageOfCollapsedView - 0.0 - isCollapsed - yes - sizes - - {{0, 0}, {470, 338}} - {{470, 0}, {373, 338}} - - - VerticalSplitView - - _collapsingFrameDimension - 0.0 - _indexOfCollapsedView - 0 - _percentageOfCollapsedView - 0.0 - isCollapsed - yes - sizes - - {{0, 0}, {843, 338}} - {{0, 338}, {843, 295}} - - - - LauncherConfigVersion - 8 - PBXProjectModuleGUID - 1C162984064C10D400B95A72 - PBXProjectModuleLabel - Debug - GLUTExamples (Underwater) - - GeometryConfiguration - - DebugConsoleVisible - None - DebugConsoleWindowFrame - {{200, 200}, {500, 300}} - DebugSTDIOWindowFrame - {{200, 200}, {500, 300}} - Frame - {{0, 0}, {843, 633}} - PBXDebugSessionStackFrameViewKey - - DebugVariablesTableConfiguration - - Name - 120 - Value - 85 - Summary - 143 - - Frame - {{470, 0}, {373, 338}} - RubberWindowFrame - -1280 264 843 674 -1280 0 1280 1024 - - RubberWindowFrame - -1280 264 843 674 -1280 0 1280 1024 - - Module - PBXDebugSessionModule - Proportion - 633pt - - - Proportion - 633pt - - - Name - Debugger - ServiceClasses - - PBXDebugSessionModule - - StatusbarIsVisible - - TableOfContents - - 1CD10A99069EF8BA00B06720 - 43150A9411E78702008C6B68 - 1C162984064C10D400B95A72 - 43150A9511E78702008C6B68 - 43150A9611E78702008C6B68 - 43150A9711E78702008C6B68 - 43150A9811E78702008C6B68 - 43150A9911E78702008C6B68 - - ToolbarConfiguration - xcode.toolbar.config.debugV3 - WindowString - -1280 264 843 674 -1280 0 1280 1024 - WindowToolGUID - 1CD10A99069EF8BA00B06720 - WindowToolIsVisible - - - - FirstTimeWindowDisplayed - - Identifier - windowTool.find - IsVertical - - Layout - - - Dock - - - Dock - - - ContentConfiguration - - PBXProjectModuleGUID - 1CDD528C0622207200134675 - PBXProjectModuleLabel - ExampleShareLink.m - StatusBarVisibility - - - GeometryConfiguration - - Frame - {{0, 0}, {981, 468}} - RubberWindowFrame - 150 74 981 890 0 0 1280 1002 - - Module - PBXNavigatorGroup - Proportion - 981pt - - - Proportion - 468pt - - - BecomeActive - - ContentConfiguration - - PBXProjectModuleGUID - 1CD0528E0623707200166675 - PBXProjectModuleLabel - Project Find - - GeometryConfiguration - - Frame - {{0, 473}, {981, 376}} - RubberWindowFrame - 150 74 981 890 0 0 1280 1002 - - Module - PBXProjectFindModule - Proportion - 376pt - - - Proportion - 849pt - - - Name - Project Find - ServiceClasses - - PBXProjectFindModule - - StatusbarIsVisible - - TableOfContents - - 1C530D57069F1CE1000CFCEE - 43FFF28B11E6633F00F9E529 - 43FFF28C11E6633F00F9E529 - 1CDD528C0622207200134675 - 1CD0528E0623707200166675 - - WindowString - 150 74 981 890 0 0 1280 1002 - WindowToolGUID - 1C530D57069F1CE1000CFCEE - WindowToolIsVisible - - - - Identifier - MENUSEPARATOR - - - FirstTimeWindowDisplayed - - Identifier - windowTool.debuggerConsole - IsVertical - - Layout - - - Dock - - - ContentConfiguration - - PBXProjectModuleGUID - 1C78EAAC065D492600B07095 - PBXProjectModuleLabel - Debugger Console - - GeometryConfiguration - - Frame - {{0, 0}, {728, 717}} - RubberWindowFrame - -1247 241 728 758 -1280 0 1280 1024 - - Module - PBXDebugCLIModule - Proportion - 717pt - - - Proportion - 717pt - - - Name - Debugger Console - ServiceClasses - - PBXDebugCLIModule - - StatusbarIsVisible - - TableOfContents - - 1C78EAAD065D492600B07095 - 43150A9A11E78702008C6B68 - 1C78EAAC065D492600B07095 - - ToolbarConfiguration - xcode.toolbar.config.consoleV3 - WindowString - -1247 241 728 758 -1280 0 1280 1024 - WindowToolGUID - 1C78EAAD065D492600B07095 - WindowToolIsVisible - - - - Identifier - windowTool.snapshots - Layout - - - Dock - - - Module - XCSnapshotModule - Proportion - 100% - - - Proportion - 100% - - - Name - Snapshots - ServiceClasses - - XCSnapshotModule - - StatusbarIsVisible - Yes - ToolbarConfiguration - xcode.toolbar.config.snapshots - WindowString - 315 824 300 550 0 0 1440 878 - WindowToolIsVisible - Yes - - - Identifier - windowTool.scm - Layout - - - Dock - - - ContentConfiguration - - PBXProjectModuleGUID - 1C78EAB2065D492600B07095 - PBXProjectModuleLabel - <No Editor> - PBXSplitModuleInNavigatorKey - - Split0 - - PBXProjectModuleGUID - 1C78EAB3065D492600B07095 - - SplitCount - 1 - - StatusBarVisibility - 1 - - GeometryConfiguration - - Frame - {{0, 0}, {452, 0}} - RubberWindowFrame - 743 379 452 308 0 0 1280 1002 - - Module - PBXNavigatorGroup - Proportion - 0pt - - - BecomeActive - 1 - ContentConfiguration - - PBXProjectModuleGUID - 1CD052920623707200166675 - PBXProjectModuleLabel - SCM - - GeometryConfiguration - - ConsoleFrame - {{0, 259}, {452, 0}} - Frame - {{0, 7}, {452, 259}} - RubberWindowFrame - 743 379 452 308 0 0 1280 1002 - TableConfiguration - - Status - 30 - FileName - 199 - Path - 197.0950012207031 - - TableFrame - {{0, 0}, {452, 250}} - - Module - PBXCVSModule - Proportion - 262pt - - - Proportion - 266pt - - - Name - SCM - ServiceClasses - - PBXCVSModule - - StatusbarIsVisible - 1 - TableOfContents - - 1C78EAB4065D492600B07095 - 1C78EAB5065D492600B07095 - 1C78EAB2065D492600B07095 - 1CD052920623707200166675 - - ToolbarConfiguration - xcode.toolbar.config.scm - WindowString - 743 379 452 308 0 0 1280 1002 - - - FirstTimeWindowDisplayed - - Identifier - windowTool.breakpoints - IsVertical - - Layout - - - Dock - - - ContentConfiguration - - PBXBottomSmartGroupGIDs - - 1C77FABC04509CD000000102 - - PBXProjectModuleGUID - 1CE0B1FE06471DED0097A5F4 - PBXProjectModuleLabel - Files - PBXProjectStructureProvided - no - PBXSmartGroupTreeModuleColumnData - - PBXSmartGroupTreeModuleColumnWidthsKey - - 168 - - PBXSmartGroupTreeModuleColumnsKey_v4 - - MainColumn - - - PBXSmartGroupTreeModuleOutlineStateKey_v7 - - PBXSmartGroupTreeModuleOutlineStateExpansionKey - - 1C77FABC04509CD000000102 - - PBXSmartGroupTreeModuleOutlineStateSelectionKey - - - 0 - - - PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 0}, {168, 350}} - - PBXTopSmartGroupGIDs - - XCIncludePerspectivesSwitch - - - GeometryConfiguration - - Frame - {{0, 0}, {185, 368}} - GroupTreeTableConfiguration - - MainColumn - 168 - - RubberWindowFrame - 42 515 744 409 0 0 1280 1002 - - Module - PBXSmartGroupTreeModule - Proportion - 185pt - - - BecomeActive - - ContentConfiguration - - PBXProjectModuleGUID - 1CA1AED706398EBD00589147 - PBXProjectModuleLabel - Detail - - GeometryConfiguration - - Frame - {{190, 0}, {554, 368}} - RubberWindowFrame - 42 515 744 409 0 0 1280 1002 - - Module - XCDetailModule - Proportion - 554pt - - - Proportion - 368pt - - - MajorVersion - 3 - MinorVersion - 0 - Name - Breakpoints - ServiceClasses - - PBXSmartGroupTreeModule - XCDetailModule - - StatusbarIsVisible - - TableOfContents - - 4312CED111CB296200E61D7A - 4312CED211CB296200E61D7A - 1CE0B1FE06471DED0097A5F4 - 1CA1AED706398EBD00589147 - - ToolbarConfiguration - xcode.toolbar.config.breakpointsV3 - WindowString - 42 515 744 409 0 0 1280 1002 - WindowToolGUID - 4312CED111CB296200E61D7A - WindowToolIsVisible - - - - Identifier - windowTool.debugAnimator - Layout - - - Dock - - - Module - PBXNavigatorGroup - Proportion - 100% - - - Proportion - 100% - - - Name - Debug Visualizer - ServiceClasses - - PBXNavigatorGroup - - StatusbarIsVisible - 1 - ToolbarConfiguration - xcode.toolbar.config.debugAnimatorV3 - WindowString - 100 100 700 500 0 0 1280 1002 - - - Identifier - windowTool.bookmarks - Layout - - - Dock - - - Module - PBXBookmarksModule - Proportion - 100% - - - Proportion - 100% - - - Name - Bookmarks - ServiceClasses - - PBXBookmarksModule - - StatusbarIsVisible - 0 - WindowString - 538 42 401 187 0 0 1280 1002 - - - Identifier - windowTool.projectFormatConflicts - Layout - - - Dock - - - Module - XCProjectFormatConflictsModule - Proportion - 100% - - - Proportion - 100% - - - Name - Project Format Conflicts - ServiceClasses - - XCProjectFormatConflictsModule - - StatusbarIsVisible - 0 - WindowContentMinSize - 450 300 - WindowString - 50 850 472 307 0 0 1440 877 - - - FirstTimeWindowDisplayed - - Identifier - windowTool.classBrowser - IsVertical - - Layout - - - Dock - - - ContentConfiguration - - OptionsSetName - Hierarchy, all classes - PBXProjectModuleGUID - 1CA6456E063B45B4001379D8 - PBXProjectModuleLabel - Class Browser - NSObject - - GeometryConfiguration - - ClassesFrame - {{0, 0}, {378, 96}} - ClassesTreeTableConfiguration - - PBXClassNameColumnIdentifier - 208 - PBXClassBookColumnIdentifier - 22 - - Frame - {{0, 0}, {630, 332}} - MembersFrame - {{0, 101}, {378, 231}} - MembersTreeTableConfiguration - - PBXMemberTypeIconColumnIdentifier - 22 - PBXMemberNameColumnIdentifier - 216 - PBXMemberTypeColumnIdentifier - 101 - PBXMemberBookColumnIdentifier - 22 - - RubberWindowFrame - 21 563 630 352 0 0 1280 1002 - - Module - PBXClassBrowserModule - Proportion - 332pt - - - Proportion - 332pt - - - Name - Class Browser - ServiceClasses - - PBXClassBrowserModule - - StatusbarIsVisible - - TableOfContents - - 1C0AD2AF069F1E9B00FABCE6 - 4374055411CFEB16005704D2 - 1CA6456E063B45B4001379D8 - - ToolbarConfiguration - xcode.toolbar.config.classbrowser - WindowString - 21 563 630 352 0 0 1280 1002 - WindowToolGUID - 1C0AD2AF069F1E9B00FABCE6 - WindowToolIsVisible - - - - Identifier - windowTool.refactoring - IncludeInToolsMenu - 0 - Layout - - - Dock - - - BecomeActive - 1 - GeometryConfiguration - - Frame - {0, 0}, {500, 335} - RubberWindowFrame - {0, 0}, {500, 335} - - Module - XCRefactoringModule - Proportion - 100% - - - Proportion - 100% - - - Name - Refactoring - ServiceClasses - - XCRefactoringModule - - WindowString - 200 200 500 356 0 0 1920 1200 - - - - diff --git a/ShareKit.xcodeproj/nate.pbxuser b/ShareKit.xcodeproj/nate.pbxuser deleted file mode 100644 index 49827e61..00000000 --- a/ShareKit.xcodeproj/nate.pbxuser +++ /dev/null @@ -1,1248 +0,0 @@ -// !$*UTF8*$! -{ - 1D6058900D05DD3D006BFB54 /* ShareKit */ = { - activeExec = 0; - executables = ( - 4362EB2811B9936600E3DB3A /* ShareKit */, - ); - }; - 28A0AAE50D9B0CCF005BE974 /* ShareKit_Prefix.pch */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1011, 865}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRange = "{0, 322}"; - }; - }; - 29B97313FDCFA39411CA2CEA /* Project object */ = { - activeBuildConfigurationName = Debug; - activeExecutable = 4362EB2811B9936600E3DB3A /* ShareKit */; - activeSDKPreference = iphonesimulator4.0; - activeTarget = 1D6058900D05DD3D006BFB54 /* ShareKit */; - addToTargets = ( - 1D6058900D05DD3D006BFB54 /* ShareKit */, - ); - breakpoints = ( - ); - codeSenseManager = 4362EB3511B9937300E3DB3A /* Code sense */; - executables = ( - 4362EB2811B9936600E3DB3A /* ShareKit */, - ); - perUserDictionary = { - "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = { - PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; - PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID; - PBXFileTableDataSourceColumnWidthsKey = ( - 20, - 20, - 198, - 20, - 99, - 99, - 29, - 20, - ); - PBXFileTableDataSourceColumnsKey = ( - PBXBreakpointsDataSource_ActionID, - PBXBreakpointsDataSource_TypeID, - PBXBreakpointsDataSource_BreakpointID, - PBXBreakpointsDataSource_UseID, - PBXBreakpointsDataSource_LocationID, - PBXBreakpointsDataSource_ConditionID, - PBXBreakpointsDataSource_IgnoreCountID, - PBXBreakpointsDataSource_ContinueID, - ); - }; - PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { - PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; - PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; - PBXFileTableDataSourceColumnWidthsKey = ( - 20, - 606, - 20, - 48, - 43, - 43, - 20, - ); - PBXFileTableDataSourceColumnsKey = ( - PBXFileDataSource_FiletypeID, - PBXFileDataSource_Filename_ColumnID, - PBXFileDataSource_Built_ColumnID, - PBXFileDataSource_ObjectSize_ColumnID, - PBXFileDataSource_Errors_ColumnID, - PBXFileDataSource_Warnings_ColumnID, - PBXFileDataSource_Target_ColumnID, - ); - }; - PBXConfiguration.PBXFileTableDataSource3.PBXFindDataSource = { - PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; - PBXFileTableDataSourceColumnSortingKey = PBXFindDataSource_LocationID; - PBXFileTableDataSourceColumnWidthsKey = ( - 200, - 716, - ); - PBXFileTableDataSourceColumnsKey = ( - PBXFindDataSource_MessageID, - PBXFindDataSource_LocationID, - ); - }; - PBXPerProjectTemplateStateSaveDate = 300385834; - PBXWorkspaceStateSaveDate = 300385834; - }; - perUserProjectItems = { - 43150A8511E7862F008C6B68 /* PBXTextBookmark */ = 43150A8511E7862F008C6B68 /* PBXTextBookmark */; - 43150A8611E7862F008C6B68 /* PBXTextBookmark */ = 43150A8611E7862F008C6B68 /* PBXTextBookmark */; - 43150A9011E78702008C6B68 /* PBXTextBookmark */ = 43150A9011E78702008C6B68 /* PBXTextBookmark */; - 43150A9111E78702008C6B68 /* PBXTextBookmark */ = 43150A9111E78702008C6B68 /* PBXTextBookmark */; - 43150A9211E78702008C6B68 /* PBXTextBookmark */ = 43150A9211E78702008C6B68 /* PBXTextBookmark */; - 43150A9311E78702008C6B68 /* PBXTextBookmark */ = 43150A9311E78702008C6B68 /* PBXTextBookmark */; - 43150A9D11E78722008C6B68 /* PBXTextBookmark */ = 43150A9D11E78722008C6B68 /* PBXTextBookmark */; - 4362EB6D11B9A14600E3DB3A = 4362EB6D11B9A14600E3DB3A /* PBXTextBookmark */; - 436A5FCD11E3F1C500622EE8 = 436A5FCD11E3F1C500622EE8 /* PBXTextBookmark */; - 436A5FD211E4128600622EE8 = 436A5FD211E4128600622EE8 /* PBXTextBookmark */; - 436A60AF11E510BD00622EE8 = 436A60AF11E510BD00622EE8 /* PBXTextBookmark */; - 439B966011E289A200ABE3BF = 439B966011E289A200ABE3BF /* PBXTextBookmark */; - 439B967B11E2926900ABE3BF = 439B967B11E2926900ABE3BF /* PBXTextBookmark */; - 439B969E11E295CC00ABE3BF = 439B969E11E295CC00ABE3BF /* PBXTextBookmark */; - 439B969F11E295CC00ABE3BF = 439B969F11E295CC00ABE3BF /* PBXTextBookmark */; - 439B96A011E295CC00ABE3BF = 439B96A011E295CC00ABE3BF /* PBXTextBookmark */; - 439B96A111E295CC00ABE3BF = 439B96A111E295CC00ABE3BF /* PBXTextBookmark */; - 439B96A711E2981100ABE3BF = 439B96A711E2981100ABE3BF /* PBXTextBookmark */; - 439B96C211E38CED00ABE3BF = 439B96C211E38CED00ABE3BF /* PBXTextBookmark */; - 439B96C411E38CED00ABE3BF = 439B96C411E38CED00ABE3BF /* PBXTextBookmark */; - 439B96C611E38CED00ABE3BF = 439B96C611E38CED00ABE3BF /* PBXTextBookmark */; - 439B975B11E3A4EC00ABE3BF = 439B975B11E3A4EC00ABE3BF /* PBXTextBookmark */; - 439B977211E3A79E00ABE3BF = 439B977211E3A79E00ABE3BF /* PBXTextBookmark */; - 439B977411E3A79E00ABE3BF = 439B977411E3A79E00ABE3BF /* PBXTextBookmark */; - 439B978611E3B2C500ABE3BF = 439B978611E3B2C500ABE3BF /* PBXTextBookmark */; - 439B97C011E3D52A00ABE3BF = 439B97C011E3D52A00ABE3BF /* PBXTextBookmark */; - 439B97CB11E3D94500ABE3BF = 439B97CB11E3D94500ABE3BF /* PBXTextBookmark */; - 43A532B211DBD7B5004A1712 = 43A532B211DBD7B5004A1712 /* PBXTextBookmark */; - 43A532B311DBD7B5004A1712 = 43A532B311DBD7B5004A1712 /* PBXTextBookmark */; - 43A532B511DBD7B5004A1712 = 43A532B511DBD7B5004A1712 /* PBXTextBookmark */; - 43A5381D11DBE42D004A1712 = 43A5381D11DBE42D004A1712 /* PBXTextBookmark */; - 43A53C6711DC0AF8004A1712 = 43A53C6711DC0AF8004A1712 /* PBXTextBookmark */; - 43A53C6811DC0AF8004A1712 = 43A53C6811DC0AF8004A1712 /* PBXTextBookmark */; - 43A53C6911DC0AF8004A1712 = 43A53C6911DC0AF8004A1712 /* PBXTextBookmark */; - 43A53C6C11DC0AF8004A1712 = 43A53C6C11DC0AF8004A1712 /* PBXTextBookmark */; - 43A53C6D11DC0AF8004A1712 = 43A53C6D11DC0AF8004A1712 /* PBXTextBookmark */; - 43A53C6F11DC0AF8004A1712 = 43A53C6F11DC0AF8004A1712 /* PBXTextBookmark */; - 43A53D1D11DD221F004A1712 = 43A53D1D11DD221F004A1712 /* PBXTextBookmark */; - 43A53D1E11DD221F004A1712 = 43A53D1E11DD221F004A1712 /* PBXTextBookmark */; - 43A53D1F11DD221F004A1712 = 43A53D1F11DD221F004A1712 /* PBXTextBookmark */; - 43A53D2011DD221F004A1712 = 43A53D2011DD221F004A1712 /* PBXTextBookmark */; - 43A53D2111DD221F004A1712 = 43A53D2111DD221F004A1712 /* PBXTextBookmark */; - 43A53D2E11DD221F004A1712 = 43A53D2E11DD221F004A1712 /* PBXTextBookmark */; - 43B665DD11DD544700BDBA80 = 43B665DD11DD544700BDBA80 /* PBXTextBookmark */; - 43B665F711DD572D00BDBA80 = 43B665F711DD572D00BDBA80 /* PBXTextBookmark */; - 43B665F811DD572D00BDBA80 = 43B665F811DD572D00BDBA80 /* PBXTextBookmark */; - 43B665F911DD572D00BDBA80 = 43B665F911DD572D00BDBA80 /* PBXTextBookmark */; - 43B665FA11DD572D00BDBA80 = 43B665FA11DD572D00BDBA80 /* PBXTextBookmark */; - 43B665FB11DD572D00BDBA80 = 43B665FB11DD572D00BDBA80 /* PBXTextBookmark */; - 43B6662611DD57D600BDBA80 = 43B6662611DD57D600BDBA80 /* PlistBookmark */; - 43B6663111DD591600BDBA80 = 43B6663111DD591600BDBA80 /* PBXTextBookmark */; - 43C3FBA611DE844F002FA9FD = 43C3FBA611DE844F002FA9FD /* PBXTextBookmark */; - 43C7D65111D93C3E00E59A6F = 43C7D65111D93C3E00E59A6F /* PBXTextBookmark */; - 43EF404B11D3FC5100B1F700 = 43EF404B11D3FC5100B1F700 /* PBXTextBookmark */; - 43EF404D11D3FC5100B1F700 = 43EF404D11D3FC5100B1F700 /* PBXTextBookmark */; - 43EF404F11D3FC5100B1F700 = 43EF404F11D3FC5100B1F700 /* PBXTextBookmark */; - 43EF405111D3FC5100B1F700 = 43EF405111D3FC5100B1F700 /* PBXTextBookmark */; - 43EF406211D3FF0200B1F700 = 43EF406211D3FF0200B1F700 /* PBXTextBookmark */; - 43FFF28D11E6CD9E00F9E529 = 43FFF28D11E6CD9E00F9E529 /* PBXTextBookmark */; - 43FFF28E11E6CD9E00F9E529 = 43FFF28E11E6CD9E00F9E529 /* PBXTextBookmark */; - 43FFF28F11E6CD9E00F9E529 = 43FFF28F11E6CD9E00F9E529 /* PBXTextBookmark */; - 43FFF29011E6CD9E00F9E529 = 43FFF29011E6CD9E00F9E529 /* PBXTextBookmark */; - }; - sourceControlManager = 4362EB3411B9937300E3DB3A /* Source Control */; - userBuildSettings = { - }; - }; - 43150A8511E7862F008C6B68 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; - name = "SHKActionSheet.m: 73"; - rLen = 0; - rLoc = 2240; - rType = 0; - vrLen = 1375; - vrLoc = 1178; - }; - 43150A8611E7862F008C6B68 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; - name = "SHKActionSheet.m: 73"; - rLen = 0; - rLoc = 2240; - rType = 0; - vrLen = 1375; - vrLoc = 1178; - }; - 43150A8C11E78697008C6B68 /* SHKInstapaper.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 2210}}"; - sepNavSelRange = "{1539, 0}"; - sepNavVisRange = "{0, 1820}"; - }; - }; - 43150A9011E78702008C6B68 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; - name = "SHKActionSheet.m: 66"; - rLen = 0; - rLoc = 2074; - rType = 0; - vrLen = 1375; - vrLoc = 1178; - }; - 43150A9111E78702008C6B68 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43150A8C11E78697008C6B68 /* SHKInstapaper.m */; - name = "SHKInstapaper.m: 40"; - rLen = 0; - rLoc = 1539; - rType = 0; - vrLen = 1820; - vrLoc = 0; - }; - 43150A9211E78702008C6B68 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367611DBE3B9004A1712 /* SHKSharer.h */; - name = "SHKSharer.h: 104"; - rLen = 0; - rLoc = 2735; - rType = 0; - vrLen = 1224; - vrLoc = 1983; - }; - 43150A9311E78702008C6B68 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 296"; - rLen = 0; - rLoc = 6333; - rType = 0; - vrLen = 1235; - vrLoc = 5410; - }; - 43150A9D11E78722008C6B68 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 296"; - rLen = 0; - rLoc = 6333; - rType = 0; - vrLen = 1779; - vrLoc = 8652; - }; - 4362EB2811B9936600E3DB3A /* ShareKit */ = { - isa = PBXExecutable; - activeArgIndices = ( - ); - argumentStrings = ( - ); - autoAttachOnCrash = 1; - breakpointsEnabled = 1; - configStateDict = { - }; - customDataFormattersEnabled = 1; - dataTipCustomDataFormattersEnabled = 1; - dataTipShowTypeColumn = 1; - dataTipSortType = 0; - debuggerPlugin = GDBDebugging; - disassemblyDisplayState = 0; - dylibVariantSuffix = ""; - enableDebugStr = 1; - environmentEntries = ( - ); - executableSystemSymbolLevel = 0; - executableUserSymbolLevel = 0; - libgmallocEnabled = 0; - name = ShareKit; - savedGlobals = { - }; - showTypeColumn = 0; - sourceDirectories = ( - ); - variableFormatDictionary = { - }; - }; - 4362EB3411B9937300E3DB3A /* Source Control */ = { - isa = PBXSourceControlManager; - fallbackIsa = XCSourceControlManager; - isSCMEnabled = 0; - scmConfiguration = { - repositoryNamesForRoots = { - "" = ""; - }; - }; - }; - 4362EB3511B9937300E3DB3A /* Code sense */ = { - isa = PBXCodeSenseManager; - indexTemplatePath = ""; - }; - 4362EB6D11B9A14600E3DB3A /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 28A0AAE50D9B0CCF005BE974 /* ShareKit_Prefix.pch */; - name = "ShareKit_Prefix.pch: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 322; - vrLoc = 0; - }; - 436A5FCD11E3F1C500622EE8 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 438D425B11C1A294001F8560 /* SHK.h */; - name = "SHK.h: 120"; - rLen = 0; - rLoc = 3326; - rType = 0; - vrLen = 1433; - vrLoc = 1894; - }; - 436A5FD211E4128600622EE8 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536A711DBE3B9004A1712 /* SHK.m */; - name = "SHK.m: 195"; - rLen = 0; - rLoc = 5283; - rType = 0; - vrLen = 1567; - vrLoc = 4611; - }; - 436A60AF11E510BD00622EE8 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; - name = "SHKSharer.m: 283"; - rLen = 20; - rLoc = 5858; - rType = 0; - vrLen = 1316; - vrLoc = 5410; - }; - 438D425B11C1A294001F8560 /* SHK.h */ = { - isa = PBXFileReference; - fileEncoding = 4; - lastKnownFileType = sourcecode.c.h; - name = SHK.h; - path = "/Users/nate/Documents/Development/ShareKit/Working Copy/Classes/ShareKit/Core/SHK.h"; - sourceTree = ""; - }; - 439B966011E289A200ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */; - name = "SHKFacebook.m: 186"; - rLen = 0; - rLoc = 4305; - rType = 0; - vrLen = 1318; - vrLoc = 3552; - }; - 439B967B11E2926900ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536B911DBE3B9004A1712 /* SHKCopy.m */; - name = "SHKCopy.m: 83"; - rLen = 0; - rLoc = 1948; - rType = 0; - vrLen = 795; - vrLoc = 1171; - }; - 439B969E11E295CC00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */; - name = "SHKTwitterForm.m: 128"; - rLen = 0; - rLoc = 3933; - rType = 0; - vrLen = 1885; - vrLoc = 3095; - }; - 439B969F11E295CC00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */; - name = "SHKActivityIndicator.m: 248"; - rLen = 102; - rLoc = 6918; - rType = 0; - vrLen = 1487; - vrLoc = 6247; - }; - 439B96A011E295CC00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F011DBE3B9004A1712 /* SHKActivityIndicator.h */; - name = "SHKActivityIndicator.h: 24"; - rLen = 0; - rLoc = 1177; - rType = 0; - vrLen = 1920; - vrLoc = 0; - }; - 439B96A111E295CC00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367611DBE3B9004A1712 /* SHKSharer.h */; - name = "SHKSharer.h: 104"; - rLen = 0; - rLoc = 2735; - rType = 0; - vrLen = 1155; - vrLoc = 2033; - }; - 439B96A711E2981100ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 439B96A811E2981100ABE3BF /* New Web Service.m */; - name = "New Web Service.m: 221"; - rLen = 22; - rLoc = 6227; - rType = 0; - vrLen = 1466; - vrLoc = 6003; - }; - 439B96A811E2981100ABE3BF /* New Web Service.m */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.objc; - name = "New Web Service.m"; - path = "/Users/nate/Documents/Development/ShareKit/Working Copy/Template Src/ShareKit/New Web Service.m"; - sourceTree = ""; - }; - 439B96C211E38CED00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */; - name = "SHKReadItLater.m: 119"; - rLen = 0; - rLoc = 3213; - rType = 0; - vrLen = 1654; - vrLoc = 2694; - }; - 439B96C411E38CED00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 439B96C511E38CED00ABE3BF /* SHKConfig.h */; - name = "SHKConfig.h: 55"; - rLen = 0; - rLoc = 2215; - rType = 0; - vrLen = 2588; - vrLoc = 1175; - }; - 439B96C511E38CED00ABE3BF /* SHKConfig.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = SHKConfig.h; - path = /Users/nate/Downloads/0.1.1/Classes/ShareKit/SHKConfig.h; - sourceTree = ""; - }; - 439B96C611E38CED00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 439B96C711E38CED00ABE3BF /* SHKConfig.h */; - name = "SHKConfig.h: 56"; - rLen = 2622; - rLoc = 2241; - rType = 0; - vrLen = 2332; - vrLoc = 2533; - }; - 439B96C711E38CED00ABE3BF /* SHKConfig.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = SHKConfig.h; - path = /Users/nate/Documents/Development/ShareKit/Releases/0.1.0/Classes/ShareKit/SHKConfig.h; - sourceTree = ""; - }; - 439B96CD11E38CED00ABE3BF /* SHKConfig.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = SHKConfig.h; - path = /Users/nate/Downloads/0.1.2/Classes/ShareKit/SHKConfig.h; - sourceTree = ""; - }; - 439B975B11E3A4EC00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 439B96CD11E38CED00ABE3BF /* SHKConfig.h */; - name = "SHKConfig.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 2410; - vrLoc = 0; - }; - 439B977211E3A79E00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EA11DBE3B9004A1712 /* SHKTwitterForm.h */; - name = "SHKTwitterForm.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 1532; - vrLoc = 0; - }; - 439B977411E3A79E00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; - name = "SHKOAuthSharer.m: 99"; - rLen = 0; - rLoc = 3069; - rType = 0; - vrLen = 1959; - vrLoc = 1915; - }; - 439B978611E3B2C500ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536BC11DBE3B9004A1712 /* SHKMail.m */; - name = "SHKMail.m: 161"; - rLen = 27; - rLoc = 3983; - rType = 0; - vrLen = 1908; - vrLoc = 2669; - }; - 439B97C011E3D52A00ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E911DBE3B9004A1712 /* SHKTwitter.m */; - name = "SHKTwitter.m: 232"; - rLen = 0; - rLoc = 6110; - rType = 0; - vrLen = 2008; - vrLoc = 5589; - }; - 439B97C311E3D52A00ABE3BF /* SHKConfig.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = SHKConfig.h; - path = /Users/nate/Documents/Development/ShareKit/Releases/0.1.2/Classes/ShareKit/SHKConfig.h; - sourceTree = ""; - }; - 439B97CB11E3D94500ABE3BF /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 439B97C311E3D52A00ABE3BF /* SHKConfig.h */; - name = "SHKConfig.h: 50"; - rLen = 0; - rLoc = 1920; - rType = 0; - vrLen = 2445; - vrLoc = 76; - }; - 43A532B211DBD7B5004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43C7E12A11DBC47E00E59A6F /* class.m */; - name = "class.m: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 223; - vrLoc = 0; - }; - 43A532B311DBD7B5004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A532B411DBD7B5004A1712 /* New Action.h */; - name = "New Action.h: 15"; - rLen = 0; - rLoc = 252; - rType = 0; - vrLen = 259; - vrLoc = 0; - }; - 43A532B411DBD7B5004A1712 /* New Action.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = "New Action.h"; - path = "/Users/nate/Library/Application Support/Developer/Shared/Xcode/File Templates/ShareKit/New Action.h"; - sourceTree = ""; - }; - 43A532B511DBD7B5004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A532B611DBD7B5004A1712 /* New Web Service.h */; - name = "New Web Service.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 259; - vrLoc = 0; - }; - 43A532B611DBD7B5004A1712 /* New Web Service.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = "New Web Service.h"; - path = "/Users/nate/Library/Application Support/Developer/Shared/Xcode/File Templates/ShareKit/New Web Service.h"; - sourceTree = ""; - }; - 43A532B811DBD7B5004A1712 /* New Web Service.m */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.objc; - name = "New Web Service.m"; - path = "/Users/nate/Library/Application Support/Developer/Shared/Xcode/File Templates/ShareKit/New Web Service.m"; - sourceTree = ""; - }; - 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1034, 3653}}"; - sepNavSelRange = "{3069, 0}"; - sepNavVisRange = "{3064, 1136}"; - sepNavWindowFrame = "{{67, 67}, {1047, 916}}"; - }; - }; - 43A5367611DBE3B9004A1712 /* SHKSharer.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {817, 2171}}"; - sepNavSelRange = "{2735, 0}"; - sepNavVisRange = "{1983, 1224}"; - }; - }; - 43A5367711DBE3B9004A1712 /* SHKSharer.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1300, 8502}}"; - sepNavSelRange = "{6333, 0}"; - sepNavVisRange = "{8652, 1779}"; - sepNavWindowFrame = "{{-1163, 72}, {1047, 916}}"; - }; - }; - 43A5367E11DBE3B9004A1712 /* SFHFKeychainUtils.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1055, 5486}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRange = "{0, 2389}"; - }; - }; - 43A5368F11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1181, 1560}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRange = "{0, 2200}"; - }; - }; - 43A5369611DBE3B9004A1712 /* OAMutableURLRequest.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 871}}"; - sepNavSelRange = "{149, 1086}"; - sepNavVisRange = "{0, 2228}"; - }; - }; - 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1622, 2964}}"; - sepNavSelRange = "{7349, 0}"; - sepNavVisRange = "{5669, 2469}"; - }; - }; - 43A536A511DBE3B9004A1712 /* SHKRequest.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {988, 1664}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRange = "{1282, 1470}"; - sepNavWindowFrame = "{{203, 59}, {1047, 916}}"; - }; - }; - 43A536A611DBE3B9004A1712 /* SHK.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 1573}}"; - sepNavSelRange = "{3326, 0}"; - sepNavVisRange = "{1894, 1433}"; - }; - }; - 43A536A711DBE3B9004A1712 /* SHK.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1314, 6318}}"; - sepNavSelRange = "{5283, 0}"; - sepNavVisRange = "{4611, 1567}"; - }; - }; - 43A536A811DBE3B9004A1712 /* SHKItem.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {831, 884}}"; - sepNavSelRange = "{1373, 22}"; - sepNavVisRange = "{74, 1444}"; - }; - }; - 43A536AB11DBE3B9004A1712 /* SHKOfflineSharer.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1219, 1716}}"; - sepNavSelRange = "{2127, 10}"; - sepNavVisRange = "{1679, 886}"; - }; - }; - 43A536AE11DBE3B9004A1712 /* SHKCustomFormController.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1219, 469}}"; - sepNavSelRange = "{1183, 0}"; - sepNavVisRange = "{0, 1319}"; - }; - }; - 43A536AF11DBE3B9004A1712 /* SHKCustomFormController.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 1742}}"; - sepNavSelRange = "{1183, 0}"; - sepNavVisRange = "{3, 2123}"; - }; - }; - 43A536B011DBE3B9004A1712 /* SHKCustomFormFieldCell.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; - sepNavSelRange = "{273, 0}"; - sepNavVisRange = "{0, 280}"; - }; - }; - 43A536B111DBE3B9004A1712 /* SHKCustomFormFieldCell.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 746}}"; - sepNavSelRange = "{1353, 0}"; - sepNavVisRange = "{0, 1353}"; - }; - }; - 43A536B911DBE3B9004A1712 /* SHKCopy.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 1157}}"; - sepNavSelRange = "{1948, 0}"; - sepNavVisRange = "{1171, 795}"; - }; - }; - 43A536BC11DBE3B9004A1712 /* SHKMail.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1244, 2405}}"; - sepNavSelRange = "{3983, 27}"; - sepNavVisRange = "{2669, 1908}"; - }; - }; - 43A536C311DBE3B9004A1712 /* SHKDelicious.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1748, 2275}}"; - sepNavSelRange = "{4770, 0}"; - sepNavVisRange = "{4141, 642}"; - sepNavWindowFrame = "{{126, 86}, {1047, 916}}"; - }; - }; - 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {920, 2574}}"; - sepNavSelRange = "{3728, 4}"; - sepNavVisRange = "{3356, 829}"; - }; - }; - 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {978, 3900}}"; - sepNavSelRange = "{8194, 0}"; - sepNavVisRange = "{6873, 1486}"; - }; - }; - 43A536E311DBE3B9004A1712 /* SHKPinboard.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1279, 2197}}"; - sepNavSelRange = "{4355, 4}"; - sepNavVisRange = "{3988, 669}"; - }; - }; - 43A536E611DBE3B9004A1712 /* SHKReadItLater.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {894, 2236}}"; - sepNavSelRange = "{3213, 0}"; - sepNavVisRange = "{2694, 1654}"; - sepNavWindowFrame = "{{145, 59}, {1047, 916}}"; - }; - }; - 43A536E911DBE3B9004A1712 /* SHKTwitter.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1335, 5109}}"; - sepNavSelRange = "{6110, 0}"; - sepNavVisRange = "{5589, 2008}"; - }; - }; - 43A536EA11DBE3B9004A1712 /* SHKTwitterForm.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 771}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRange = "{0, 1532}"; - }; - }; - 43A536EB11DBE3B9004A1712 /* SHKTwitterForm.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1174, 2548}}"; - sepNavSelRange = "{3933, 0}"; - sepNavVisRange = "{3543, 1074}"; - }; - }; - 43A536EC11DBE3B9004A1712 /* SHKConfig.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {985, 1690}}"; - sepNavSelRange = "{1258, 0}"; - sepNavVisRange = "{0, 2590}"; - sepNavWindowFrame = "{{-1242, 82}, {1047, 916}}"; - }; - }; - 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {929, 1300}}"; - sepNavSelRange = "{2074, 0}"; - sepNavVisRange = "{1178, 1375}"; - }; - }; - 43A536F011DBE3B9004A1712 /* SHKActivityIndicator.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {784, 780}}"; - sepNavSelRange = "{1177, 0}"; - sepNavVisRange = "{0, 1920}"; - }; - }; - 43A536F111DBE3B9004A1712 /* SHKActivityIndicator.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1426, 3614}}"; - sepNavSelRange = "{6918, 102}"; - sepNavVisRange = "{6247, 1487}"; - }; - }; - 43A536F211DBE3B9004A1712 /* SHKFormController.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {988, 832}}"; - sepNavSelRange = "{237, 0}"; - sepNavVisRange = "{40, 1304}"; - sepNavWindowFrame = "{{-1196, 40}, {1047, 916}}"; - }; - }; - 43A536F311DBE3B9004A1712 /* SHKFormController.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {920, 3640}}"; - sepNavSelRange = "{2924, 4}"; - sepNavVisRange = "{2289, 933}"; - }; - }; - 43A536F811DBE3B9004A1712 /* SHKNavController.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRange = "{0, 236}"; - }; - }; - 43A536FA11DBE3B9004A1712 /* SHKOAuthView.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1111, 724}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRange = "{0, 861}"; - }; - }; - 43A536FC11DBE3B9004A1712 /* SHKShareMenu.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRange = "{0, 707}"; - }; - }; - 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {957, 4212}}"; - sepNavSelRange = "{7565, 0}"; - sepNavVisRange = "{7119, 884}"; - }; - }; - 43A5381D11DBE42D004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A532B811DBD7B5004A1712 /* New Web Service.m */; - name = "New Web Service.m: 16"; - rLen = 0; - rLoc = 225; - rType = 0; - vrLen = 225; - vrLoc = 0; - }; - 43A5382F11DBE493004A1712 /* ExampleShareLink.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1139, 1027}}"; - sepNavSelRange = "{2101, 14}"; - sepNavVisRange = "{1346, 1257}"; - }; - }; - 43A5383111DBE493004A1712 /* ExampleShareText.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1219, 1170}}"; - sepNavSelRange = "{86, 1093}"; - sepNavVisRange = "{0, 1372}"; - }; - }; - 43A53C0711DC07A9004A1712 /* SHKCustomShareMenuCell.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; - sepNavSelRange = "{417, 22}"; - sepNavVisRange = "{0, 554}"; - }; - }; - 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {892, 413}}"; - sepNavSelRange = "{171, 0}"; - sepNavVisRange = "{0, 306}"; - }; - }; - 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; - sepNavSelRange = "{338, 0}"; - sepNavVisRange = "{0, 345}"; - }; - }; - 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */ = { - uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {706, 724}}"; - sepNavSelRange = "{211, 82}"; - sepNavVisRange = "{0, 301}"; - }; - }; - 43A53C6711DC0AF8004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F811DBE3B9004A1712 /* SHKNavController.h */; - name = "SHKNavController.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 236; - vrLoc = 0; - }; - 43A53C6811DC0AF8004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536FA11DBE3B9004A1712 /* SHKOAuthView.h */; - name = "SHKOAuthView.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 861; - vrLoc = 0; - }; - 43A53C6911DC0AF8004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536FC11DBE3B9004A1712 /* SHKShareMenu.h */; - name = "SHKShareMenu.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 707; - vrLoc = 0; - }; - 43A53C6C11DC0AF8004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A53C0711DC07A9004A1712 /* SHKCustomShareMenuCell.h */; - name = "SHKCustomShareMenuCell.h: 21"; - rLen = 22; - rLoc = 1453; - rType = 0; - vrLen = 554; - vrLoc = 0; - }; - 43A53C6D11DC0AF8004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */; - name = "SHKCustomShareMenuCell.m: 14"; - rLen = 82; - rLoc = 1253; - rType = 0; - vrLen = 306; - vrLoc = 0; - }; - 43A53C6F11DC0AF8004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */; - name = "SHKCustomShareMenu.m: 14"; - rLen = 82; - rLoc = 1247; - rType = 0; - vrLen = 301; - vrLoc = 0; - }; - 43A53D1D11DD221F004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */; - name = "SHKShareMenu.m: 191"; - rLen = 0; - rLoc = 5838; - rType = 0; - vrLen = 1748; - vrLoc = 3493; - }; - 43A53D1E11DD221F004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536F211DBE3B9004A1712 /* SHKFormController.h */; - name = "SHKFormController.h: 11"; - rLen = 0; - rLoc = 1273; - rType = 0; - vrLen = 1224; - vrLoc = 0; - }; - 43A53D1F11DD221F004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536B011DBE3B9004A1712 /* SHKCustomFormFieldCell.h */; - name = "SHKCustomFormFieldCell.h: 15"; - rLen = 0; - rLoc = 1309; - rType = 0; - vrLen = 280; - vrLoc = 0; - }; - 43A53D2011DD221F004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536AE11DBE3B9004A1712 /* SHKCustomFormController.h */; - name = "SHKCustomFormController.h: 12"; - rLen = 0; - rLoc = 1307; - rType = 0; - vrLen = 283; - vrLoc = 0; - }; - 43A53D2111DD221F004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */; - name = "SHKCustomShareMenu.h: 19"; - rLen = 0; - rLoc = 1374; - rType = 0; - vrLen = 345; - vrLoc = 0; - }; - 43A53D2E11DD221F004A1712 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536C311DBE3B9004A1712 /* SHKDelicious.m */; - name = "SHKDelicious.m: 55"; - rLen = 361; - rLoc = 2339; - rType = 0; - vrLen = 1443; - vrLoc = 608; - }; - 43B665DD11DD544700BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536A811DBE3B9004A1712 /* SHKItem.h */; - name = "SHKItem.h: 62"; - rLen = 22; - rLoc = 2409; - rType = 0; - vrLen = 1444; - vrLoc = 74; - }; - 43B665F711DD572D00BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5367E11DBE3B9004A1712 /* SFHFKeychainUtils.m */; - name = "SFHFKeychainUtils.m: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 2389; - vrLoc = 0; - }; - 43B665F811DD572D00BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5368F11DBE3B9004A1712 /* OAAsynchronousDataFetcher.m */; - name = "OAAsynchronousDataFetcher.m: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 2200; - vrLoc = 0; - }; - 43B665F911DD572D00BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5369611DBE3B9004A1712 /* OAMutableURLRequest.h */; - name = "OAMutableURLRequest.h: 8"; - rLen = 1086; - rLoc = 149; - rType = 0; - vrLen = 2228; - vrLoc = 0; - }; - 43B665FA11DD572D00BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536AF11DBE3B9004A1712 /* SHKCustomFormController.m */; - name = "SHKCustomFormController.m: 25"; - rLen = 0; - rLoc = 1183; - rType = 0; - vrLen = 2123; - vrLoc = 3; - }; - 43B665FB11DD572D00BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536B111DBE3B9004A1712 /* SHKCustomFormFieldCell.m */; - name = "SHKCustomFormFieldCell.m: 36"; - rLen = 0; - rLoc = 1353; - rType = 0; - vrLen = 1353; - vrLoc = 0; - }; - 43B6662611DD57D600BDBA80 /* PlistBookmark */ = { - isa = PlistBookmark; - fRef = 43A536AC11DBE3B9004A1712 /* SHKSharers.plist */; - fallbackIsa = PBXBookmark; - isK = 0; - kPath = ( - ); - name = "/Users/nate/Documents/Development/ShareKit/Working Copy/Classes/ShareKit/Core/SHKSharers.plist"; - rLen = 0; - rLoc = 9223372036854775808; - }; - 43B6663111DD591600BDBA80 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536E011DBE3B9004A1712 /* SHKGoogleReader.m */; - name = "SHKGoogleReader.m: 293"; - rLen = 0; - rLoc = 8194; - rType = 0; - vrLen = 1486; - vrLoc = 6873; - }; - 43C3FBA611DE844F002FA9FD /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */; - name = "OAMutableURLRequest.m: 209"; - rLen = 0; - rLoc = 7349; - rType = 0; - vrLen = 2469; - vrLoc = 5669; - }; - 43C7D65111D93C3E00E59A6F /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43C7D65211D93C3E00E59A6F /* OAMutableURLRequest.h */; - name = "OAMutableURLRequest.h: 55"; - rLen = 0; - rLoc = 2031; - rType = 0; - vrLen = 1129; - vrLoc = 1295; - }; - 43C7D65211D93C3E00E59A6F /* OAMutableURLRequest.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = OAMutableURLRequest.h; - path = "/Users/nate/Documents/tmp/oauth-read-only/OAMutableURLRequest.h"; - sourceTree = ""; - }; - 43C7E12A11DBC47E00E59A6F /* class.m */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.objc; - name = class.m; - path = "/Developer/Library/Xcode/File Templates/Cocoa Class/Objective-C class/Objective-C class.pbfiletemplate/class.m"; - sourceTree = ""; - }; - 43EF404B11D3FC5100B1F700 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43EF404C11D3FC5100B1F700 /* NSMutableURLRequest+Parameters.h */; - name = "NSMutableURLRequest+Parameters.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 1609; - vrLoc = 0; - }; - 43EF404C11D3FC5100B1F700 /* NSMutableURLRequest+Parameters.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = "NSMutableURLRequest+Parameters.h"; - path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/Categories/NSMutableURLRequest+Parameters.h"; - sourceTree = ""; - }; - 43EF404D11D3FC5100B1F700 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43EF404E11D3FC5100B1F700 /* NSString+URLEncoding.h */; - name = "NSString+URLEncoding.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 1441; - vrLoc = 0; - }; - 43EF404E11D3FC5100B1F700 /* NSString+URLEncoding.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = "NSString+URLEncoding.h"; - path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/Categories/NSString+URLEncoding.h"; - sourceTree = ""; - }; - 43EF404F11D3FC5100B1F700 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43EF405011D3FC5100B1F700 /* NSURL+Base.h */; - name = "NSURL+Base.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 1344; - vrLoc = 0; - }; - 43EF405011D3FC5100B1F700 /* NSURL+Base.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = "NSURL+Base.h"; - path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/Categories/NSURL+Base.h"; - sourceTree = ""; - }; - 43EF405111D3FC5100B1F700 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43EF405211D3FC5100B1F700 /* OAToken_KeychainExtensions.h */; - name = "OAToken_KeychainExtensions.h: 1"; - rLen = 0; - rLoc = 0; - rType = 0; - vrLen = 583; - vrLoc = 0; - }; - 43EF405211D3FC5100B1F700 /* OAToken_KeychainExtensions.h */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.h; - name = OAToken_KeychainExtensions.h; - path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/OAToken_KeychainExtensions.h"; - sourceTree = ""; - }; - 43EF405411D3FC5100B1F700 /* OAToken_KeychainExtensions.m */ = { - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.objc; - name = OAToken_KeychainExtensions.m; - path = "/Users/nate/Downloads/amazingsyco-oauthconsumer-69bce30 3/OAToken_KeychainExtensions.m"; - sourceTree = ""; - }; - 43EF406211D3FF0200B1F700 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43EF405411D3FC5100B1F700 /* OAToken_KeychainExtensions.m */; - name = "OAToken_KeychainExtensions.m: 79"; - rLen = 29; - rLoc = 2662; - rType = 0; - vrLen = 1564; - vrLoc = 1852; - }; - 43FFF28D11E6CD9E00F9E529 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EC11DBE3B9004A1712 /* SHKConfig.h */; - name = "SHKConfig.h: 31"; - rLen = 0; - rLoc = 1258; - rType = 0; - vrLen = 2590; - vrLoc = 0; - }; - 43FFF28E11E6CD9E00F9E529 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A5382F11DBE493004A1712 /* ExampleShareLink.m */; - name = "ExampleShareLink.m: 59"; - rLen = 14; - rLoc = 2101; - rType = 0; - vrLen = 2071; - vrLoc = 548; - }; - 43FFF28F11E6CD9E00F9E529 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; - name = "SHKActionSheet.m: 45"; - rLen = 14; - rLoc = 1452; - rType = 0; - vrLen = 1375; - vrLoc = 1178; - }; - 43FFF29011E6CD9E00F9E529 /* PBXTextBookmark */ = { - isa = PBXTextBookmark; - fRef = 43A536EF11DBE3B9004A1712 /* SHKActionSheet.m */; - name = "SHKActionSheet.m: 45"; - rLen = 14; - rLoc = 1452; - rType = 0; - vrLen = 1375; - vrLoc = 1178; - }; -} From 6f1ca7b31deed9578d25f6d24eb2baa1580a10c6 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Mon, 12 Jul 2010 13:49:32 -0700 Subject: [PATCH 10/50] New Configuration Options: - Debug switch - ModalPresentationStyle (for iPad apps) - ModalTransitionStyle (for iPad apps) New Features: - Logout of all services +[SHK logoutOfAll] - Logout of specific service +[SHK logoutOfService:serviceId] Critical Fixes: - Delicious token expiring after 1 hour - Bit.ly could return non-bit.ly domains causing shortened url to be rejected Minor Improvements: - SHKActionSheet tried to act on indexes less than 0 - Cancelling OAuth login no longer prompts 'user cancelled' error message Other bug fixes --- .gitignore | 1 + Classes/Example/ExampleShareLink.m | 2 +- Classes/Example/ShareKitAppDelegate.m | 12 +- .../Core/Base Sharer Classes/SHKOAuthSharer.h | 2 + .../Core/Base Sharer Classes/SHKOAuthSharer.m | 87 ++++- .../Core/Base Sharer Classes/SHKSharer.h | 18 +- .../Core/Base Sharer Classes/SHKSharer.m | 41 ++- .../Helpers/OAuth/OAAsynchronousDataFetcher.h | 2 +- .../Core/Helpers/OAuth/OAMutableURLRequest.m | 3 +- Classes/ShareKit/Core/Helpers/OAuth/OAToken.h | 2 + Classes/ShareKit/Core/Helpers/OAuth/OAToken.m | 6 +- Classes/ShareKit/Core/Helpers/SHKRequest.m | 3 +- Classes/ShareKit/Core/SHK.h | 8 +- Classes/ShareKit/Core/SHK.m | 106 ++++-- Classes/ShareKit/Core/SHKSharers.plist | 2 +- Classes/ShareKit/SHKConfig.h | 49 ++- .../Sharers/Services/Delicious/SHKDelicious.m | 43 ++- .../Sharers/Services/Facebook/SHKFacebook.h | 4 +- .../Sharers/Services/Facebook/SHKFacebook.m | 18 +- .../Services/Google Reader/SHKGoogleReader.m | 6 +- .../Services/Instapaper/SHKInstapaper.m | 12 +- .../Sharers/Services/Pinboard/SHKPinboard.m | 4 +- .../Services/Read It Later/SHKReadItLater.m | 4 +- .../Sharers/Services/Twitter/SHKTwitter.h | 4 +- .../Sharers/Services/Twitter/SHKTwitter.m | 27 +- Classes/ShareKit/UI/SHKActionSheet.m | 2 +- Classes/ShareKit/UI/SHKOAuthView.h | 1 + Classes/ShareKit/UI/SHKOAuthView.m | 2 +- Classes/ShareKit/UI/SHKShareMenu.m | 2 +- Resources-iPad/MainWindow-iPad.xib | 304 ++++++++++++++++++ ShareKit-Info.plist | 2 + ShareKit.xcodeproj/project.pbxproj | 68 ++-- 32 files changed, 702 insertions(+), 145 deletions(-) create mode 100644 Resources-iPad/MainWindow-iPad.xib diff --git a/.gitignore b/.gitignore index 3bf3dee7..b68a679e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.pbxuser *.perspectivev3 +*.mode1v3 build diff --git a/Classes/Example/ExampleShareLink.m b/Classes/Example/ExampleShareLink.m index cef5fe77..aa2ba202 100644 --- a/Classes/Example/ExampleShareLink.m +++ b/Classes/Example/ExampleShareLink.m @@ -65,7 +65,7 @@ - (void)loadView self.webView = [[UIWebView alloc] initWithFrame:CGRectZero]; webView.delegate = self; webView.scalesPageToFit = YES; - [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://apple.com/"]]]; + [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://apple.com"]]]; self.view = webView; } diff --git a/Classes/Example/ShareKitAppDelegate.m b/Classes/Example/ShareKitAppDelegate.m index 01f51ae3..c9c6a0bc 100644 --- a/Classes/Example/ShareKitAppDelegate.m +++ b/Classes/Example/ShareKitAppDelegate.m @@ -30,24 +30,18 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( navigationController.topViewController.title = @"Examples"; [navigationController setToolbarHidden:NO]; - [self performSelector:@selector(test) withObject:nil afterDelay:0.5]; + [self performSelector:@selector(testOffline) withObject:nil afterDelay:0.5]; return YES; } -- (void)test +- (void)testOffline { [SHK flushOfflineQueue]; - //[SHKFacebook shareURL:[NSURL URLWithString:@"http://ideashower.com"]]; } -- (void)test2 +- (void)applicationWillTerminate:(UIApplication *)application { - [[SHKActivityIndicator currentIndicator] displayCompleted:@"Saved!"]; -} - - -- (void)applicationWillTerminate:(UIApplication *)application { // Save data if appropriate } diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.h b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.h index 2d45b512..9bcfec55 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.h +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.h @@ -78,12 +78,14 @@ - (void)tokenAuthorize; - (void)tokenAccess; +- (void)tokenAccess:(BOOL)refresh; - (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest; - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data; - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error; - (void)storeAccessToken; - (BOOL)restoreAccessToken; +- (void)refreshToken; @end diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m index 21b37a3c..3cc07392 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m @@ -95,9 +95,6 @@ - (void)tokenRequest didFailSelector:@selector(tokenRequestTicket:didFailWithError:)]; [fetcher start]; [oRequest release]; - - //NSLog(@"%@", oRequest.URL); - //NSLog(@"request %@", [[NSString alloc] initWithData:[oRequest HTTPBody] encoding:NSUTF8StringEncoding]); } - (void)tokenRequestModifyRequest:(OAMutableURLRequest *)oRequest @@ -107,7 +104,8 @@ - (void)tokenRequestModifyRequest:(OAMutableURLRequest *)oRequest - (void)tokenRequestTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data { - //NSLog(@"tokenRequestTicketResponse %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); + if (SHKDebugShowLogs) // check so we don't have to alloc the string with the data if we aren't logging + SHKLog(@"tokenRequestTicket Response Body: %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); [[SHKActivityIndicator currentIndicator] hide]; @@ -170,16 +168,27 @@ - (void)tokenAuthorizeView:(SHKOAuthView *)authView didFinishWithSuccess:(BOOL)s } } +- (void)tokenAuthorizeCancelledView:(SHKOAuthView *)authView +{ + [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; +} + #pragma mark Access - (void)tokenAccess -{ - [[SHKActivityIndicator currentIndicator] displayActivity:@"Authenticating..."]; +{ + [self tokenAccess:NO]; +} + +- (void)tokenAccess:(BOOL)refresh +{ + if (!refresh) + [[SHKActivityIndicator currentIndicator] displayActivity:@"Authenticating..."]; OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:accessURL consumer:consumer - token:requestToken + token:(refresh ? accessToken : requestToken) realm:nil // our service provider doesn't specify a realm signatureProvider:signatureProvider]; // use the default method, HMAC-SHA1 @@ -202,7 +211,8 @@ - (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data { - //NSLog(@"tokenAccessTicketResponse %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); + if (SHKDebugShowLogs) // check so we don't have to alloc the string with the data if we aren't logging + SHKLog(@"tokenAccessTicket Response Body: %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); [[SHKActivityIndicator currentIndicator] hide]; @@ -215,8 +225,7 @@ - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *) [self storeAccessToken]; - if (shareAfterAuth) - [self share]; + [self tryPendingAction]; } @@ -244,7 +253,26 @@ - (void)storeAccessToken [SHK setAuthValue:accessToken.secret forKey:@"accessSecret" - forSharer:[self sharerId]]; + forSharer:[self sharerId]]; + + [SHK setAuthValue:accessToken.sessionHandle + forKey:@"sessionHandle" + forSharer:[self sharerId]]; +} + ++ (void)deleteStoredAccessToken +{ + [SHK setAuthValue:nil + forKey:@"accessKey" + forSharer:[self sharerId]]; + + [SHK setAuthValue:nil + forKey:@"accessSecret" + forSharer:[self sharerId]]; + + [SHK setAuthValue:nil + forKey:@"sessionHandle" + forSharer:[self sharerId]]; } - (BOOL)restoreAccessToken @@ -258,15 +286,50 @@ - (BOOL)restoreAccessToken forSharer:[self sharerId]]; NSString *secret = [SHK getAuthValueForKey:@"accessSecret" - forSharer:[self sharerId]]; + forSharer:[self sharerId]]; + + NSString *sessionHandle = [SHK getAuthValueForKey:@"sessionHandle" + forSharer:[self sharerId]]; if (key != nil && secret != nil) { self.accessToken = [[[OAToken alloc] initWithKey:key secret:secret] autorelease]; + + if (sessionHandle != nil) + accessToken.sessionHandle = sessionHandle; + return accessToken != nil; } return NO; } + +#pragma mark Expired + +- (void)refreshToken +{ + self.pendingAction = SHKPendingRefreshToken; + [self tokenAccess:YES]; +} + +#pragma mark - +#pragma mark Pending Actions +#pragma mark - +#pragma mark Pending Actions + +- (void)tryPendingAction +{ + switch (pendingAction) + { + case SHKPendingRefreshToken: + [self tryToSend]; // try to resend + break; + + default: + [super tryPendingAction]; + } +} + + @end diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h index be5bef51..424b432e 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h @@ -42,6 +42,13 @@ @end +typedef enum +{ + SHKPendingNone, + SHKPendingShare, + SHKPendingRefreshToken +} SHKSharerPendingAction; + @interface SHKSharer : UINavigationController { @@ -54,7 +61,7 @@ NSError *lastError; BOOL quiet; - BOOL shareAfterAuth; + SHKSharerPendingAction pendingAction; } @property (nonatomic, retain) id shareDelegate; @@ -66,7 +73,7 @@ @property (nonatomic, retain) NSError *lastError; @property BOOL quiet; -@property BOOL shareAfterAuth; +@property SHKSharerPendingAction pendingAction; @@ -135,6 +142,8 @@ - (void)authorizationFormSave:(SHKFormController *)form; - (NSArray *)authorizationFormFields; - (NSString *)authorizationFormCaption; ++ (NSArray *)authorizationFormFields; ++ (NSString *)authorizationFormCaption; #pragma mark - @@ -156,6 +165,11 @@ - (void)shareFormValidate:(SHKFormController *)form; - (void)shareFormSave:(SHKFormController *)form; +#pragma mark - +#pragma mark Pending Actions + +- (void)tryPendingAction; + #pragma mark - #pragma mark Delegate Notifications diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m index ac903819..c5616170 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m @@ -33,7 +33,7 @@ @implementation SHKSharer @synthesize shareDelegate; @synthesize item, pendingForm, request; @synthesize lastError; -@synthesize quiet, shareAfterAuth; +@synthesize quiet, pendingAction; - (void)dealloc { @@ -163,6 +163,12 @@ - (id)init { self.shareDelegate = self; self.item = [[[SHKItem alloc] init] autorelease]; + + if ([self respondsToSelector:@selector(modalPresentationStyle)]) + self.modalPresentationStyle = [SHK modalPresentationStyle]; + + if ([self respondsToSelector:@selector(modalTransitionStyle)]) + self.modalTransitionStyle = [SHK modalTransitionStyle]; } return self; } @@ -267,7 +273,7 @@ - (void)share { // isAuthorized - If service requires login and details have not been saved, present login dialog if (![self authorize]) - self.shareAfterAuth = YES; + self.pendingAction = SHKPendingShare; // A. First check if auto share is set // B. If it is, try to send @@ -394,6 +400,11 @@ - (void)authorizationFormSave:(SHKFormController *)form } - (NSArray *)authorizationFormFields +{ + return [[self class] authorizationFormFields]; +} + ++ (NSArray *)authorizationFormFields { return [NSArray arrayWithObjects: [SHKFormFieldSettings label:@"Username" key:@"username" type:SHKFormFieldTypeText start:nil], @@ -402,6 +413,11 @@ - (NSArray *)authorizationFormFields } - (NSString *)authorizationFormCaption +{ + return [[self class] authorizationFormCaption]; +} + ++ (NSString *)authorizationFormCaption { return nil; } @@ -613,6 +629,19 @@ - (void)sharerCancelledSending:(SHKSharer *)sharer } +#pragma mark - +#pragma mark Pending Actions + +- (void)tryPendingAction +{ + switch (pendingAction) + { + case SHKPendingShare: + [self share]; + break; + } +} + #pragma mark - @@ -622,6 +651,14 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface return YES; } +- (void)viewDidDisappear:(BOOL)animated +{ + [super viewDidDisappear:animated]; + + // Remove the SHK view wrapper from the window + [[SHK currentHelper] viewWasDismissed]; +} + #pragma mark - #pragma mark Delegate Notifications diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.h b/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.h index 20a23152..dd6c0498 100644 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.h +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAAsynchronousDataFetcher.h @@ -33,7 +33,7 @@ NSMutableData *responseData; id delegate; SEL didFinishSelector; - SEL didFailSelector; + SEL didFailSelector; } + (id)asynchronousFetcherWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m index d32f759a..5327b895 100755 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m @@ -25,6 +25,7 @@ #import "OAMutableURLRequest.h" +#import "SHKConfig.h" @interface OAMutableURLRequest (Private) @@ -223,7 +224,7 @@ - (NSString *)_signatureBaseString [[[self URL] URLStringWithoutQuery] URLEncodedString], [normalizedRequestParameters URLEncodedString]]; - //NSLog(@"ret %@", ret); + SHKLog(@"OAMutableURLRequest parameters %@", normalizedRequestParameters); return ret; } diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAToken.h b/Classes/ShareKit/Core/Helpers/OAuth/OAToken.h index 8dd331e1..e9904d7e 100755 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAToken.h +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAToken.h @@ -29,9 +29,11 @@ @protected NSString *key; NSString *secret; + NSString *sessionHandle; } @property(retain) NSString *key; @property(retain) NSString *secret; +@property(retain) NSString *sessionHandle; - (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; - (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAToken.m b/Classes/ShareKit/Core/Helpers/OAuth/OAToken.m index d4f24911..22c4b9d1 100755 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAToken.m +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAToken.m @@ -29,7 +29,7 @@ @implementation OAToken -@synthesize key, secret; +@synthesize key, secret, sessionHandle; #pragma mark init @@ -39,6 +39,7 @@ - (id)init { self.key = @""; self.secret = @""; + self.sessionHandle = @""; } return self; } @@ -65,6 +66,8 @@ - (id)initWithHTTPResponseBody:(NSString *)body self.key = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_secret"]) { self.secret = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_session_handle"]) { + self.sessionHandle = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; } } } @@ -89,6 +92,7 @@ - (void)dealloc { [key release]; [secret release]; + [sessionHandle release]; [super dealloc]; } diff --git a/Classes/ShareKit/Core/Helpers/SHKRequest.m b/Classes/ShareKit/Core/Helpers/SHKRequest.m index 7d619f28..4603d2e5 100644 --- a/Classes/ShareKit/Core/Helpers/SHKRequest.m +++ b/Classes/ShareKit/Core/Helpers/SHKRequest.m @@ -26,6 +26,7 @@ // #import "SHKRequest.h" +#import "SHKConfig.h" #define SHK_TIMEOUT 90 @@ -94,7 +95,7 @@ - (void)start } // Start Connection - //NSLog(@"SHKRequest: %@?%@\n\n%@", url, params, [request allHTTPHeaderFields]); + SHKLog(@"Start SHKRequest:\nURL: %@\nparams: %@", url, params); self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; [request release]; [connection release]; diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index 46d0fa94..9988083f 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -52,7 +52,7 @@ NSOperationQueue *offlineQueue; } -@property (nonatomic, retain) UIViewController *rootViewController; +@property (nonatomic, assign) UIViewController *rootViewController; @property (nonatomic, retain) UIViewController *currentView; @property (nonatomic, retain) UIViewController *pendingView; @property BOOL isDismissingView; @@ -75,7 +75,10 @@ - (void)hideCurrentViewControllerAnimated:(BOOL)animated; - (void)viewWasDismissed; - (UIViewController *)getTopViewController; + + (UIBarStyle)barStyle; ++ (UIModalPresentationStyle)modalPresentationStyle; ++ (UIModalTransitionStyle)modalTransitionStyle; #pragma mark - #pragma mark Favorites @@ -94,6 +97,9 @@ + (NSString *)getAuthValueForKey:(NSString *)key forSharer:(NSString *)sharerId; + (void)setAuthValue:(NSString *)value forKey:(NSString *)key forSharer:(NSString *)sharerId; ++ (void)logoutOfAll; ++ (void)logoutOfService:(NSString *)sharerId; + #pragma mark - #pragma mark Offline Support diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m index d6b88744..c95d51d1 100644 --- a/Classes/ShareKit/Core/SHK.m +++ b/Classes/ShareKit/Core/SHK.m @@ -28,7 +28,6 @@ #import "SHK.h" #import "SHKActivityIndicator.h" #import "SHKViewControllerWrapper.h" -#import "SHKNavController.h" #import "SHKActionSheet.h" #import "SHKOfflineSharer.h" #import "SFHFKeychainUtils.h" @@ -37,7 +36,8 @@ @implementation SHK -@synthesize rootViewController, currentView, pendingView, isDismissingView; +@synthesize currentView, pendingView, isDismissingView; +@synthesize rootViewController; @synthesize offlineQueue; static SHK *currentHelper = nil; @@ -55,7 +55,6 @@ + (SHK *)currentHelper - (void)dealloc { - [rootViewController release]; [currentView release]; [pendingView release]; [offlineQueue release]; @@ -68,8 +67,9 @@ - (void)dealloc #pragma mark View Management + (void)setRootViewController:(UIViewController *)vc -{ - [[self currentHelper] setRootViewController:vc]; +{ + SHK *helper = [self currentHelper]; + [helper setRootViewController:vc]; } - (void)showViewController:(UIViewController *)vc @@ -118,9 +118,16 @@ - (void)showViewController:(UIViewController *)vc if (![vc respondsToSelector:@selector(pushViewController:animated:)]) { UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:vc] autorelease]; - [topViewController presentModalViewController:nav animated:YES]; - nav.navigationBar.barStyle = - nav.toolbar.barStyle = [SHK barStyle]; + + if ([nav respondsToSelector:@selector(modalPresentationStyle)]) + nav.modalPresentationStyle = [SHK modalPresentationStyle]; + + if ([nav respondsToSelector:@selector(modalTransitionStyle)]) + nav.modalTransitionStyle = [SHK modalTransitionStyle]; + + nav.navigationBar.barStyle = nav.toolbar.barStyle = [SHK barStyle]; + + [topViewController presentModalViewController:nav animated:YES]; self.currentView = nav; } @@ -176,21 +183,49 @@ - (UIViewController *)getTopViewController topViewController = topViewController.modalViewController; return topViewController; } - + + (UIBarStyle)barStyle { if ([SHKBarStyle isEqualToString:@"UIBarStyleBlack"]) return UIBarStyleBlack; - - else if ([SHKBarStyle isEqualToString:@"UIBarStyleBlack"]) - return UIBarStyleBlackOpaque; - else if ([SHKBarStyle isEqualToString:@"UIBarStyleBlack"]) - return UIBarStyleBlackTranslucent; + else if ([SHKBarStyle isEqualToString:@"UIBarStyleBlackOpaque"]) + return UIBarStyleBlackOpaque; + + else if ([SHKBarStyle isEqualToString:@"UIBarStyleBlackTranslucent"]) + return UIBarStyleBlackTranslucent; return UIBarStyleDefault; } ++ (UIModalPresentationStyle)modalPresentationStyle +{ + if ([SHKModalPresentationStyle isEqualToString:@"UIModalPresentationFullScreen"]) + return UIModalPresentationFullScreen; + + else if ([SHKModalPresentationStyle isEqualToString:@"UIModalPresentationPageSheet"]) + return UIModalPresentationPageSheet; + + else if ([SHKModalPresentationStyle isEqualToString:@"UIModalPresentationFormSheet"]) + return UIModalPresentationFormSheet; + + return UIModalPresentationCurrentContext; +} + ++ (UIModalTransitionStyle)modalTransitionStyle +{ + if ([SHKModalTransitionStyle isEqualToString:@"UIModalTransitionStyleFlipHorizontal"]) + return UIModalTransitionStyleFlipHorizontal; + + else if ([SHKModalTransitionStyle isEqualToString:@"UIModalTransitionStyleCrossDissolve"]) + return UIModalTransitionStyleCrossDissolve; + + else if ([SHKModalTransitionStyle isEqualToString:@"UIModalTransitionStylePartialCurl"]) + return UIModalTransitionStylePartialCurl; + + return UIModalTransitionStyleCoverVertical; +} + #pragma mark - #pragma mark Favorites @@ -266,9 +301,7 @@ + (void)setUserExclusions:(NSDictionary *)exclusions #pragma mark - #pragma mark Credentials -#define SHK_AUTH_PREFIX @"SHK_AUTH_" - -// TODO someone with more keychain experience may want to clean this up. The use of SFHFKeychainUtils may be unnecessary bloat? +// TODO someone with more keychain experience may want to clean this up. The use of SFHFKeychainUtils may be unnecessary? + (NSString *)getAuthValueForKey:(NSString *)key forSharer:(NSString *)sharerId { @@ -276,9 +309,9 @@ + (NSString *)getAuthValueForKey:(NSString *)key forSharer:(NSString *)sharerId // Using NSUserDefaults for storage is very insecure, but because Keychain only exists on a device // we use NSUserDefaults when running on the simulator to store objects. This allows you to still test // in the simulator. You should NOT modify in a way that does not use keychain when actually deployed to a device. - return [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"%@_%@_%@",SHK_AUTH_PREFIX,sharerId,key]]; + return [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"%@%@%@",SHK_AUTH_PREFIX,sharerId,key]]; #else - return [SFHFKeychainUtils getPasswordForUsername:key andServiceName:sharerId error:nil]; + return [SFHFKeychainUtils getPasswordForUsername:key andServiceName:[NSString stringWithFormat:@"%@%@",SHK_AUTH_PREFIX,sharerId] error:nil]; #endif } @@ -288,12 +321,43 @@ + (void)setAuthValue:(NSString *)value forKey:(NSString *)key forSharer:(NSStrin // Using NSUserDefaults for storage is very insecure, but because Keychain only exists on a device // we use NSUserDefaults when running on the simulator to store objects. This allows you to still test // in the simulator. You should NOT modify in a way that does not use keychain when actually deployed to a device. - [[NSUserDefaults standardUserDefaults] setObject:value forKey:[NSString stringWithFormat:@"%@_%@_%@",SHK_AUTH_PREFIX,sharerId,key]]; + [[NSUserDefaults standardUserDefaults] setObject:value forKey:[NSString stringWithFormat:@"%@%@%@",SHK_AUTH_PREFIX,sharerId,key]]; #else - [SFHFKeychainUtils storeUsername:key andPassword:value forServiceName:sharerId updateExisting:YES error:nil]; + [SFHFKeychainUtils storeUsername:key andPassword:value forServiceName:[NSString stringWithFormat:@"%@%@",SHK_AUTH_PREFIX,sharerId] updateExisting:YES error:nil]; #endif } ++ (void)logoutOfAll +{ + NSArray *sharers = [[SHK sharersDictionary] objectForKey:@"services"]; + for (NSString *sharerId in sharers) + [self logoutOfService:sharerId]; +} + ++ (void)logoutOfService:(NSString *)sharerId +{ + // TODO - can we just clear the keychain of a specific service name in one go rather than enumerating through each auth value? + + SHKSharer *class = (SHKSharer *)NSClassFromString(sharerId); + + // oauth web service + if ([class respondsToSelector:@selector(deleteStoredAccessToken)]) + [class performSelector:@selector(deleteStoredAccessToken)]; + + // web service + else + { + NSArray *authFields = [class authorizationFormFields]; + if (authFields != nil) + { + for(SHKFormFieldSettings *field in authFields) + [SHK setAuthValue:nil forKey:field.key forSharer:sharerId]; + } + } + + +} + #pragma mark - diff --git a/Classes/ShareKit/Core/SHKSharers.plist b/Classes/ShareKit/Core/SHKSharers.plist index 5e742992..b5ba9244 100644 --- a/Classes/ShareKit/Core/SHKSharers.plist +++ b/Classes/ShareKit/Core/SHKSharers.plist @@ -10,7 +10,6 @@ services - SHKTumblr SHKTwitter SHKPinboard SHKDelicious @@ -18,6 +17,7 @@ SHKFacebook SHKReadItLater SHKInstapaper + SHKTumblr diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index f7058fe8..e7f8ed7d 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -38,21 +38,21 @@ /* -API Keys --------- -This is the longest step to getting set up, it involves filling in API keys for the supported services. -It should be pretty painless though and should hopefully take no more than a few minutes. + API Keys + -------- + This is the longest step to getting set up, it involves filling in API keys for the supported services. + It should be pretty painless though and should hopefully take no more than a few minutes. -Each key below as a link to a page where you can generate an api key. Fill in the key for each service below. + Each key below as a link to a page where you can generate an api key. Fill in the key for each service below. -A note on services you don't need: -If, for example, your app only shares URLs then you probably won't need image services like Flickr. -In these cases it is safe to leave an API key blank. + A note on services you don't need: + If, for example, your app only shares URLs then you probably won't need image services like Flickr. + In these cases it is safe to leave an API key blank. -However, it is STRONGLY recommended that you do your best to support all services for the types of sharing you support. -The core principle behind ShareKit is to leave the service choices up to the user. Thus, you should not remove any services, -leaving that decision up to the user. -*/ + However, it is STRONGLY recommended that you do your best to support all services for the types of sharing you support. + The core principle behind ShareKit is to leave the service choices up to the user. Thus, you should not remove any services, + leaving that decision up to the user. + */ @@ -105,6 +105,10 @@ leaving that decision up to the user. #define SHKFormBgColorGreen -1 // Value between 0-255, set all to -1 for default #define SHKFormBgColorBlue -1 // Value between 0-255, set all to -1 for default +// iPad views +#define SHKModalPresentationStyle @"UIModalPresentationFormSheet" // See: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle +#define SHKModalTransitionStyle @"UIModalTransitionStyleCoverVertical" // See: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle + /* UI Configuration : Advanced @@ -115,6 +119,27 @@ leaving that decision up to the user. +/* + Debugging + ------ + To show debug output in the console: + 1. uncomment section A below + 2. comment out section B below + + To hide debug output in the console: + 1. uncomment section B below + 2. comment out section A below + */ + +// A : show debug output +//#define SHKDebugShowLogs 1 +//#define SHKLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) + +// B : hide debug output +#define SHKDebugShowLogs 0 +#define SHKLog( s, ... ) + + /* Advanced Configuration diff --git a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m index eb030834..832b122b 100644 --- a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m +++ b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m @@ -28,6 +28,14 @@ #import "SHKDelicious.h" #import "OAuthConsumer.h" + +// You can leave this be. The user will actually never see this url. ShareKit just looks for +// when delicious redirects to this url and intercepts it. It can be any url. +#define SHKDeliciousCallbackUrl @"http://getsharekit.com/oauthcallback" + + +// http://github.com/jdg/oauthconsumer/blob/master/OATokenManager.m + @implementation SHKDelicious @@ -78,7 +86,14 @@ - (void)tokenRequestModifyRequest:(OAMutableURLRequest *)oRequest - (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest { - [oRequest setOAuthParameterName:@"oauth_verifier" withValue:[authorizeResponseQueryVars objectForKey:@"oauth_verifier"]]; + if (pendingAction == SHKPendingRefreshToken) + { + if (accessToken.sessionHandle != nil) + [oRequest setOAuthParameterName:@"oauth_session_handle" withValue:accessToken.sessionHandle]; + } + + else + [oRequest setOAuthParameterName:@"oauth_verifier" withValue:[authorizeResponseQueryVars objectForKey:@"oauth_verifier"]]; } - (BOOL)handleResponse:(SHKRequest *)aRequest @@ -168,16 +183,36 @@ - (BOOL)send return NO; } + - (void)sendTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data -{ +{ if (ticket.didSucceed && [ticket.body rangeOfString:@"\"done\""].location != NSNotFound) { // Do anything? } else - // TODO - better error handling - [self sendTicket:ticket didFailWithError:[SHK error:@"There was a problem saving to Delicious"]]; + { + if (SHKDebugShowLogs) // check so we don't have to alloc the string with the data if we aren't logging + SHKLog(@"SHKDelicious sendTicket Response Body: %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); + + // Look for oauth problems + // TODO - I'd prefer to use regex for this but that would require OS4 or adding a regex library + NSError *error; + NSString *body = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + + // Expired token + if ([body rangeOfString:@"token_expired"].location != NSNotFound) + { + [self refreshToken]; + return; + } + + else + error = [SHK error:@"There was a problem saving to Delicious"]; + + [self sendTicket:ticket didFailWithError:error]; + } // Notify delegate [self sendDidFinish]; diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h index 18cbbde0..ab0ee137 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.h @@ -41,12 +41,12 @@ typedef enum @interface SHKFacebook : SHKSharer { FBSession *session; - SHKFacebookPendingAction pendingAction; + SHKFacebookPendingAction pendingFacebookAction; FBLoginDialog *login; } @property (retain) FBSession *session; -@property SHKFacebookPendingAction pendingAction; +@property SHKFacebookPendingAction pendingFacebookAction; @property (retain) FBLoginDialog *login; @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 5e5fdf39..708d75c2 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -31,7 +31,7 @@ @implementation SHKFacebook @synthesize session; -@synthesize pendingAction; +@synthesize pendingFacebookAction; @synthesize login; @@ -97,7 +97,7 @@ - (BOOL)isAuthorized - (void)promptAuthorization { - self.pendingAction = SHKFacebookPendingLogin; + self.pendingFacebookAction = SHKFacebookPendingLogin; self.login = [[[FBLoginDialog alloc] init] autorelease]; [login show]; } @@ -114,7 +114,7 @@ - (BOOL)send { if (item.shareType == SHKShareTypeURL) { - self.pendingAction = SHKFacebookPendingStatus; + self.pendingFacebookAction = SHKFacebookPendingStatus; FBStreamDialog* dialog = [[[FBStreamDialog alloc] init] autorelease]; dialog.delegate = self; @@ -136,7 +136,7 @@ - (BOOL)send else if (item.shareType == SHKShareTypeImage) { - self.pendingAction = SHKFacebookPendingImage; + self.pendingFacebookAction = SHKFacebookPendingImage; FBPermissionDialog* dialog = [[[FBPermissionDialog alloc] init] autorelease]; dialog.delegate = self; @@ -158,18 +158,18 @@ - (void)sendImage - (void)dialogDidSucceed:(FBDialog*)dialog { - if (pendingAction == SHKFacebookPendingImage) + if (pendingFacebookAction == SHKFacebookPendingImage) [self sendImage]; // TODO - the dialog has a SKIP button. Skipping still calls this even though it doesn't appear to post. // - need to intercept the skip and handle it as a cancel? - else if (pendingAction == SHKFacebookPendingStatus) + else if (pendingFacebookAction == SHKFacebookPendingStatus) [self sendDidFinish]; } - (void)dialogDidCancel:(FBDialog*)dialog { - if (pendingAction == SHKFacebookPendingStatus) + if (pendingFacebookAction == SHKFacebookPendingStatus) [self sendDidCancel]; } @@ -184,9 +184,9 @@ - (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL*)url - (void)session:(FBSession*)session didLogin:(FBUID)uid { // Try to share again - if (pendingAction == SHKFacebookPendingLogin) + if (pendingFacebookAction == SHKFacebookPendingLogin) { - self.pendingAction = SHKFacebookPendingNone; + self.pendingFacebookAction = SHKFacebookPendingNone; [self share]; } } diff --git a/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m index cc90ec4c..1b84ae3d 100644 --- a/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m +++ b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m @@ -70,12 +70,12 @@ + (BOOL)canShareURL #pragma mark - #pragma mark Authorization -- (NSString *)authorizationFormCaption ++ (NSString *)authorizationFormCaption { - return @"Set up a free account at http://google.com/reader"; + return @"Create a free account at Google.com/reader"; } -- (NSArray *)authorizationFormFields ++ (NSArray *)authorizationFormFields { return [NSArray arrayWithObjects: [SHKFormFieldSettings label:@"Email" key:@"email" type:SHKFormFieldTypeText start:nil], diff --git a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m index acada8d9..94ca9a79 100755 --- a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m +++ b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m @@ -55,9 +55,9 @@ + (BOOL)canShare #pragma mark - #pragma mark Authorization -- (NSString *)authorizationFormCaption ++ (NSString *)authorizationFormCaption { - return @"Set up a free account at http://instapaper.com"; + return @"Create a free account at Instapaper.com"; } - (void)authorizationFormValidate:(SHKFormController *)form @@ -95,9 +95,9 @@ - (void)authFinished:(SHKRequest *)aRequest else { NSString *errorMessage = nil; if (aRequest.response.statusCode == 403) - errorMessage = @"Invalid username or password."; + errorMessage = @"Sorry, Instapaper did not accept your credentials. Please try again."; else - errorMessage = @"The service encountered an error. Please try again later."; + errorMessage = @"Sorry, Instapaper encountered an error. Please try again."; [[[[UIAlertView alloc] initWithTitle:@"Login Error" message:errorMessage @@ -148,10 +148,10 @@ - (void)sendFinished:(SHKRequest *)aRequest { if (!aRequest.success) { if (aRequest.response.statusCode == 403) { - [self sendDidFailWithError:[SHK error:@"Invalid username or password."] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:@"Sorry, Instapaper did not accept your credentials. Please try again."] shouldRelogin:YES]; return; } - else if (aRequest.response.statusCode == 500) { + else if (aRequest.response.statusCode == 500) { [self sendDidFailWithError:[SHK error:@"The service encountered an error. Please try again later."]]; return; } diff --git a/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m index 24f864c5..04deeaf7 100644 --- a/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m +++ b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m @@ -49,9 +49,9 @@ + (BOOL)canShareURL #pragma mark - #pragma mark Authorization -- (NSString *)authorizationFormCaption ++ (NSString *)authorizationFormCaption { - return @"Set up an account at http://pinboard.in"; + return @"Create an account at http://pinboard.in"; } - (void)authorizationFormValidate:(SHKFormController *)form diff --git a/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m b/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m index 9df5880e..ca954a2a 100644 --- a/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m +++ b/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m @@ -61,9 +61,9 @@ - (BOOL)shouldAutoShare #pragma mark - #pragma mark Authorization -- (NSString *)authorizationFormCaption ++ (NSString *)authorizationFormCaption { - return @"Set up a free account at http://readitlaterlist.com"; + return @"Create a free account at Readitlaterlist.com"; } - (void)authorizationFormValidate:(SHKFormController *)form diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h index 2dce32ef..57569157 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h @@ -31,12 +31,10 @@ @interface SHKTwitter : SHKOAuthSharer { - BOOL xAuth; - NSString *myTwitterUsername; + BOOL xAuth; } @property BOOL xAuth; -@property (nonatomic, retain) NSString *myTwitterUsername; #pragma mark - diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index 53a848ba..b5f49722 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -33,21 +33,11 @@ @implementation SHKTwitter @synthesize xAuth; -@synthesize myTwitterUsername; - -- (void)dealloc -{ - [myTwitterUsername release]; - [super dealloc]; -} - (id)init { if (self = [super init]) - { - // Enter your app's twitter account if you'd like to ask the user to follow it when logging in - self.myTwitterUsername = [SHKTwitterUsername isEqualToString:@""] ? nil : SHKTwitterUsername; - + { // OAUTH self.consumerKey = SHKTwitterConsumerKey; self.secretKey = SHKTwitterSecret; @@ -123,20 +113,20 @@ - (void)promptAuthorization #pragma mark xAuth -- (NSString *)authorizationFormCaption ++ (NSString *)authorizationFormCaption { - return @"Sign up for a free account at http://twitter.com"; + return @"Create a free account at Twitter.com"; } -- (NSArray *)authorizationFormFields ++ (NSArray *)authorizationFormFields { - if (myTwitterUsername == nil) + if ([SHKTwitterUsername isEqualToString:@""]) return [super authorizationFormFields]; return [NSArray arrayWithObjects: [SHKFormFieldSettings label:@"Username" key:@"username" type:SHKFormFieldTypeText start:nil], [SHKFormFieldSettings label:@"Password" key:@"password" type:SHKFormFieldTypePassword start:nil], - [SHKFormFieldSettings label:[NSString stringWithFormat:@"Follow %@",myTwitterUsername] key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], + [SHKFormFieldSettings label:[NSString stringWithFormat:@"Follow %@",SHKTwitterUsername] key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], nil]; } @@ -257,7 +247,7 @@ - (void)shortenURLFinished:(SHKRequest *)aRequest NSString *result = [[aRequest getResult] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; - if ([result rangeOfString:@"http://bit.ly"].location == NSNotFound) + if (result == nil || [NSURL URLWithString:result] == nil) { // TODO - better error message [[[[UIAlertView alloc] initWithTitle:@"Shorten URL Error" @@ -341,6 +331,7 @@ - (void)sendStatusTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)d { // TODO better error handling here + if (ticket.didSucceed) [self sendDidFinish]; @@ -359,7 +350,7 @@ - (void)followMe // remove it so in case of other failures this doesn't get hit again [item setCustomValue:nil forKey:@"followMe"]; - OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://api.twitter.com/1/friendships/create/%@.json", myTwitterUsername]] + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://api.twitter.com/1/friendships/create/%@.json", SHKTwitterUsername]] consumer:consumer token:accessToken realm:nil diff --git a/Classes/ShareKit/UI/SHKActionSheet.m b/Classes/ShareKit/UI/SHKActionSheet.m index a103c831..6011b72f 100644 --- a/Classes/ShareKit/UI/SHKActionSheet.m +++ b/Classes/ShareKit/UI/SHKActionSheet.m @@ -84,7 +84,7 @@ + (SHKActionSheet *)actionSheetForItem:(SHKItem *)i - (void)actionSheet:(SHKActionSheet *)as clickedButtonAtIndex:(NSInteger)buttonIndex { // Sharers - if (buttonIndex < as.sharers.count) + if (buttonIndex >= 0 && buttonIndex < as.sharers.count) { [objc_getClass([[as.sharers objectAtIndex:buttonIndex] UTF8String]) performSelector:@selector(shareItem:) withObject:item]; } diff --git a/Classes/ShareKit/UI/SHKOAuthView.h b/Classes/ShareKit/UI/SHKOAuthView.h index ed9160a8..7604ee51 100644 --- a/Classes/ShareKit/UI/SHKOAuthView.h +++ b/Classes/ShareKit/UI/SHKOAuthView.h @@ -33,6 +33,7 @@ @protocol SHKOAuthViewDelegate - (void)tokenAuthorizeView:(SHKOAuthView *)authView didFinishWithSuccess:(BOOL)success queryParams:(NSMutableDictionary *)queryParams error:(NSError *)error; +- (void)tokenAuthorizeCancelledView:(SHKOAuthView *)authView; - (NSURL *)authorizeCallbackURL; @end diff --git a/Classes/ShareKit/UI/SHKOAuthView.m b/Classes/ShareKit/UI/SHKOAuthView.m index 1b1e252c..4dd2da88 100644 --- a/Classes/ShareKit/UI/SHKOAuthView.m +++ b/Classes/ShareKit/UI/SHKOAuthView.m @@ -151,7 +151,7 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface - (void)cancel { - [delegate tokenAuthorizeView:self didFinishWithSuccess:NO queryParams:nil error:[SHK error:@"User cancelled login"]]; + [delegate tokenAuthorizeCancelledView:self]; [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; } diff --git a/Classes/ShareKit/UI/SHKShareMenu.m b/Classes/ShareKit/UI/SHKShareMenu.m index 47ee7f2d..4018d599 100644 --- a/Classes/ShareKit/UI/SHKShareMenu.m +++ b/Classes/ShareKit/UI/SHKShareMenu.m @@ -161,7 +161,7 @@ - (NSMutableArray *)section:(NSString *)section { id class; NSMutableArray *sectionData = [NSMutableArray arrayWithCapacity:0]; - NSArray *source = [[SHK sharersDictionary] objectForKey:section];; + NSArray *source = [[SHK sharersDictionary] objectForKey:section]; for( NSString *sharerClassName in source) { diff --git a/Resources-iPad/MainWindow-iPad.xib b/Resources-iPad/MainWindow-iPad.xib new file mode 100644 index 00000000..7497640a --- /dev/null +++ b/Resources-iPad/MainWindow-iPad.xib @@ -0,0 +1,304 @@ + + + + 1024 + 10D573 + 788 + 1038.29 + 460.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 117 + + + YES + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + YES + + + YES + + + + YES + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + IBCocoaTouchFramework + + + + 1316 + + {320, 480} + + 1 + MSAxIDEAA + + NO + NO + + IBCocoaTouchFramework + YES + + + + + 1 + + IBCocoaTouchFramework + NO + + + 256 + {0, 0} + NO + YES + YES + IBCocoaTouchFramework + + + YES + + + IBCocoaTouchFramework + + + RootViewController + + + 1 + + IBCocoaTouchFramework + NO + + + + + + + YES + + + delegate + + + + 4 + + + + window + + + + 5 + + + + navigationController + + + + 15 + + + + + YES + + 0 + + + + + + 2 + + + YES + + + + + -1 + + + File's Owner + + + 3 + + + + + -2 + + + + + 9 + + + YES + + + + + + + 11 + + + + + 13 + + + YES + + + + + + 14 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 11.IBPluginDependency + 13.CustomClassName + 13.IBPluginDependency + 2.IBAttributePlaceholdersKey + 2.IBEditorWindowLastContentRect + 2.IBPluginDependency + 3.CustomClassName + 3.IBPluginDependency + 9.IBEditorWindowLastContentRect + 9.IBPluginDependency + + + YES + UIApplication + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + RootViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + YES + + + YES + + + {{673, 376}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + ShareKitAppDelegate + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + {{186, 376}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + YES + + + + + YES + + + YES + + + + 15 + + + + YES + + RootViewController + UITableViewController + + IBProjectSource + Classes/RootViewController.h + + + + ShareKitAppDelegate + NSObject + + YES + + YES + navigationController + window + + + YES + UINavigationController + UIWindow + + + + YES + + YES + navigationController + window + + + YES + + navigationController + UINavigationController + + + window + UIWindow + + + + + IBProjectSource + Classes/ShareKitAppDelegate.h + + + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + ShareKit.xcodeproj + 3 + 117 + + diff --git a/ShareKit-Info.plist b/ShareKit-Info.plist index 32894445..d5dc4bd3 100644 --- a/ShareKit-Info.plist +++ b/ShareKit-Info.plist @@ -26,5 +26,7 @@ NSMainNibFile MainWindow + NSMainNibFile~ipad + MainWindow-iPad diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index e2f166ab..c878351a 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD735F0D9D9599002E5188 /* MainWindow.xib */; }; 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28F335F01007B36200424DE2 /* RootViewController.xib */; }; 4312CF7C11CB33E200E61D7A /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4312CF7B11CB33E200E61D7A /* MessageUI.framework */; }; + 43150A8D11E78697008C6B68 /* SHKInstapaper.m in Sources */ = {isa = PBXBuildFile; fileRef = 43150A8C11E78697008C6B68 /* SHKInstapaper.m */; }; 43A5370011DBE3B9004A1712 /* SHKOAuthSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; }; 43A5370111DBE3B9004A1712 /* SHKSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; }; 43A5370211DBE3B9004A1712 /* UIWebView+SHK.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367A11DBE3B9004A1712 /* UIWebView+SHK.m */; }; @@ -30,7 +31,6 @@ 43A5370D11DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369511DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.m */; }; 43A5370E11DBE3B9004A1712 /* OAMutableURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */; }; 43A5370F11DBE3B9004A1712 /* OAPlaintextSignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369911DBE3B9004A1712 /* OAPlaintextSignatureProvider.m */; }; - 43A5371011DBE3B9004A1712 /* OAProblem.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369B11DBE3B9004A1712 /* OAProblem.m */; }; 43A5371111DBE3B9004A1712 /* OARequestParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369D11DBE3B9004A1712 /* OARequestParameter.m */; }; 43A5371211DBE3B9004A1712 /* OAServiceTicket.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5369F11DBE3B9004A1712 /* OAServiceTicket.m */; }; 43A5371311DBE3B9004A1712 /* OAToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536A211DBE3B9004A1712 /* OAToken.m */; }; @@ -68,7 +68,6 @@ 43A5373311DBE3B9004A1712 /* SHKFormController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F311DBE3B9004A1712 /* SHKFormController.m */; }; 43A5373411DBE3B9004A1712 /* SHKFormFieldCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F511DBE3B9004A1712 /* SHKFormFieldCell.m */; }; 43A5373511DBE3B9004A1712 /* SHKFormFieldSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F711DBE3B9004A1712 /* SHKFormFieldSettings.m */; }; - 43A5373611DBE3B9004A1712 /* SHKNavController.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536F911DBE3B9004A1712 /* SHKNavController.m */; }; 43A5373711DBE3B9004A1712 /* SHKOAuthView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536FB11DBE3B9004A1712 /* SHKOAuthView.m */; }; 43A5373811DBE3B9004A1712 /* SHKShareMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */; }; 43A5373911DBE3B9004A1712 /* SHKViewControllerWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A536FF11DBE3B9004A1712 /* SHKViewControllerWrapper.m */; }; @@ -82,9 +81,10 @@ 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */; }; 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */; }; 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */; }; + 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */; }; + 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */; }; 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; 43EF406E11D3FFF800B1F700 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43EF406D11D3FFF800B1F700 /* Security.framework */; }; - E88E853711E8C4C90089EB8B /* SHKTumblr.m in Sources */ = {isa = PBXBuildFile; fileRef = E88E853611E8C4C90089EB8B /* SHKTumblr.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -96,9 +96,9 @@ 28AD735F0D9D9599002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 28F335F01007B36200424DE2 /* RootViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RootViewController.xib; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 3D384B5111E6AD2000C8056C /* SHKInstapaper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SHKInstapaper.m; path = Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m; sourceTree = SOURCE_ROOT; }; - 3D384B5211E6AD2000C8056C /* SHKInstapaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SHKInstapaper.h; path = Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.h; sourceTree = SOURCE_ROOT; }; 4312CF7B11CB33E200E61D7A /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; + 43150A8B11E78697008C6B68 /* SHKInstapaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKInstapaper.h; sourceTree = ""; }; + 43150A8C11E78697008C6B68 /* SHKInstapaper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKInstapaper.m; sourceTree = ""; }; 43A5367411DBE3B9004A1712 /* SHKOAuthSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOAuthSharer.h; sourceTree = ""; }; 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOAuthSharer.m; sourceTree = ""; }; 43A5367611DBE3B9004A1712 /* SHKSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKSharer.h; sourceTree = ""; }; @@ -131,8 +131,6 @@ 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAMutableURLRequest.m; sourceTree = ""; }; 43A5369811DBE3B9004A1712 /* OAPlaintextSignatureProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAPlaintextSignatureProvider.h; sourceTree = ""; }; 43A5369911DBE3B9004A1712 /* OAPlaintextSignatureProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAPlaintextSignatureProvider.m; sourceTree = ""; }; - 43A5369A11DBE3B9004A1712 /* OAProblem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAProblem.h; sourceTree = ""; }; - 43A5369B11DBE3B9004A1712 /* OAProblem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAProblem.m; sourceTree = ""; }; 43A5369C11DBE3B9004A1712 /* OARequestParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OARequestParameter.h; sourceTree = ""; }; 43A5369D11DBE3B9004A1712 /* OARequestParameter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OARequestParameter.m; sourceTree = ""; }; 43A5369E11DBE3B9004A1712 /* OAServiceTicket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAServiceTicket.h; sourceTree = ""; }; @@ -209,8 +207,6 @@ 43A536F511DBE3B9004A1712 /* SHKFormFieldCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFormFieldCell.m; sourceTree = ""; }; 43A536F611DBE3B9004A1712 /* SHKFormFieldSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFormFieldSettings.h; sourceTree = ""; }; 43A536F711DBE3B9004A1712 /* SHKFormFieldSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFormFieldSettings.m; sourceTree = ""; }; - 43A536F811DBE3B9004A1712 /* SHKNavController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKNavController.h; sourceTree = ""; }; - 43A536F911DBE3B9004A1712 /* SHKNavController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKNavController.m; sourceTree = ""; }; 43A536FA11DBE3B9004A1712 /* SHKOAuthView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOAuthView.h; sourceTree = ""; }; 43A536FB11DBE3B9004A1712 /* SHKOAuthView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOAuthView.m; sourceTree = ""; }; 43A536FC11DBE3B9004A1712 /* SHKShareMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKShareMenu.h; sourceTree = ""; }; @@ -235,11 +231,12 @@ 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenuCell.m; sourceTree = ""; }; 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCustomShareMenu.h; sourceTree = ""; }; 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenu.m; sourceTree = ""; }; + 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "MainWindow-iPad.xib"; path = "Resources-iPad/MainWindow-iPad.xib"; sourceTree = ""; }; + 43C91DF311EBAE4800F31FAE /* SHKTumblr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKTumblr.h; sourceTree = ""; }; + 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTumblr.m; sourceTree = ""; }; 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 43EF406D11D3FFF800B1F700 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 8D1107310486CEB800E47090 /* ShareKit-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ShareKit-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; - E88E853511E8C4C90089EB8B /* SHKTumblr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKTumblr.h; sourceTree = ""; }; - E88E853611E8C4C90089EB8B /* SHKTumblr.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTumblr.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -282,6 +279,7 @@ 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, + 43C91D1B11EB963600F31FAE /* Resources-iPad */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); @@ -322,11 +320,11 @@ name = Frameworks; sourceTree = ""; }; - 3D384B4D11E6ACF700C8056C /* Instapaper */ = { + 43150A8A11E78697008C6B68 /* Instapaper */ = { isa = PBXGroup; children = ( - 3D384B5211E6AD2000C8056C /* SHKInstapaper.h */, - 3D384B5111E6AD2000C8056C /* SHKInstapaper.m */, + 43150A8B11E78697008C6B68 /* SHKInstapaper.h */, + 43150A8C11E78697008C6B68 /* SHKInstapaper.m */, ); path = Instapaper; sourceTree = ""; @@ -437,8 +435,6 @@ 43A5369711DBE3B9004A1712 /* OAMutableURLRequest.m */, 43A5369811DBE3B9004A1712 /* OAPlaintextSignatureProvider.h */, 43A5369911DBE3B9004A1712 /* OAPlaintextSignatureProvider.m */, - 43A5369A11DBE3B9004A1712 /* OAProblem.h */, - 43A5369B11DBE3B9004A1712 /* OAProblem.m */, 43A5369C11DBE3B9004A1712 /* OARequestParameter.h */, 43A5369D11DBE3B9004A1712 /* OARequestParameter.m */, 43A5369E11DBE3B9004A1712 /* OAServiceTicket.h */, @@ -544,13 +540,13 @@ 43A536C011DBE3B9004A1712 /* Services */ = { isa = PBXGroup; children = ( - E88E853411E8C4B00089EB8B /* Tumblr */, 43A536C111DBE3B9004A1712 /* Delicious */, 43A536C411DBE3B9004A1712 /* Facebook */, 43A536DE11DBE3B9004A1712 /* Google Reader */, - 3D384B4D11E6ACF700C8056C /* Instapaper */, + 43150A8A11E78697008C6B68 /* Instapaper */, 43A536E111DBE3B9004A1712 /* Pinboard */, 43A536E411DBE3B9004A1712 /* Read It Later */, + 43C91DF211EBAE4800F31FAE /* Tumblr */, 43A536E711DBE3B9004A1712 /* Twitter */, ); path = Services; @@ -659,8 +655,6 @@ 43A536FD11DBE3B9004A1712 /* SHKShareMenu.m */, 43A536FA11DBE3B9004A1712 /* SHKOAuthView.h */, 43A536FB11DBE3B9004A1712 /* SHKOAuthView.m */, - 43A536F811DBE3B9004A1712 /* SHKNavController.h */, - 43A536F911DBE3B9004A1712 /* SHKNavController.m */, 43A536FE11DBE3B9004A1712 /* SHKViewControllerWrapper.h */, 43A536FF11DBE3B9004A1712 /* SHKViewControllerWrapper.m */, ); @@ -689,11 +683,19 @@ name = Form; sourceTree = ""; }; - E88E853411E8C4B00089EB8B /* Tumblr */ = { + 43C91D1B11EB963600F31FAE /* Resources-iPad */ = { isa = PBXGroup; children = ( - E88E853511E8C4C90089EB8B /* SHKTumblr.h */, - E88E853611E8C4C90089EB8B /* SHKTumblr.m */, + 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */, + ); + name = "Resources-iPad"; + sourceTree = ""; + }; + 43C91DF211EBAE4800F31FAE /* Tumblr */ = { + isa = PBXGroup; + children = ( + 43C91DF311EBAE4800F31FAE /* SHKTumblr.h */, + 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */, ); path = Tumblr; sourceTree = ""; @@ -753,6 +755,7 @@ 43A5372011DBE3B9004A1712 /* FBConnect.bundle in Resources */, 43A5382811DBE480004A1712 /* example.pdf in Resources */, 43A5382911DBE480004A1712 /* sanFran.jpg in Resources */, + 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -780,7 +783,6 @@ 43A5370D11DBE3B9004A1712 /* OAHMAC_SHA1SignatureProvider.m in Sources */, 43A5370E11DBE3B9004A1712 /* OAMutableURLRequest.m in Sources */, 43A5370F11DBE3B9004A1712 /* OAPlaintextSignatureProvider.m in Sources */, - 43A5371011DBE3B9004A1712 /* OAProblem.m in Sources */, 43A5371111DBE3B9004A1712 /* OARequestParameter.m in Sources */, 43A5371211DBE3B9004A1712 /* OAServiceTicket.m in Sources */, 43A5371311DBE3B9004A1712 /* OAToken.m in Sources */, @@ -816,7 +818,6 @@ 43A5373311DBE3B9004A1712 /* SHKFormController.m in Sources */, 43A5373411DBE3B9004A1712 /* SHKFormFieldCell.m in Sources */, 43A5373511DBE3B9004A1712 /* SHKFormFieldSettings.m in Sources */, - 43A5373611DBE3B9004A1712 /* SHKNavController.m in Sources */, 43A5373711DBE3B9004A1712 /* SHKOAuthView.m in Sources */, 43A5373811DBE3B9004A1712 /* SHKShareMenu.m in Sources */, 43A5373911DBE3B9004A1712 /* SHKViewControllerWrapper.m in Sources */, @@ -828,7 +829,8 @@ 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */, 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */, 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */, - E88E853711E8C4C90089EB8B /* SHKTumblr.m in Sources */, + 43150A8D11E78697008C6B68 /* SHKInstapaper.m in Sources */, + 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -839,14 +841,17 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = ShareKit_Prefix.pch; INFOPLIST_FILE = "ShareKit-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; PRODUCT_NAME = ShareKit; SDKROOT = iphoneos4.0; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -854,12 +859,15 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = ShareKit_Prefix.pch; INFOPLIST_FILE = "ShareKit-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 3.2; PRODUCT_NAME = ShareKit; SDKROOT = iphoneos4.0; + TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -872,8 +880,10 @@ GCC_C_LANGUAGE_STANDARD = c99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.1; PREBINDING = NO; - SDKROOT = iphoneos3.1.3; + SDKROOT = iphoneos4.0; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -885,9 +895,11 @@ GCC_C_LANGUAGE_STANDARD = c99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 3.1; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; PREBINDING = NO; - SDKROOT = iphoneos3.1.3; + SDKROOT = iphoneos4.0; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; From b7baddd9f3dc0e9e531baef7dc1e0969d5b8d33f Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Mon, 12 Jul 2010 14:09:50 -0700 Subject: [PATCH 11/50] last minute cleanups before releasing 0.1.5 --- .../ShareKit/Core/Helpers/OAuth/OAProblem.h | 53 ------ .../ShareKit/Core/Helpers/OAuth/OAProblem.m | 165 ------------------ Classes/ShareKit/SHKConfig.h | 1 - Classes/ShareKit/UI/SHKNavController.h | 36 ---- Classes/ShareKit/UI/SHKNavController.m | 38 ---- 5 files changed, 293 deletions(-) delete mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAProblem.h delete mode 100755 Classes/ShareKit/Core/Helpers/OAuth/OAProblem.m delete mode 100644 Classes/ShareKit/UI/SHKNavController.h delete mode 100644 Classes/ShareKit/UI/SHKNavController.m diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.h b/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.h deleted file mode 100755 index fe64c700..00000000 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// OAProblem.h -// OAuthConsumer -// -// Created by Alberto García Hierro on 03/09/08. -// Copyright 2008 Alberto García Hierro. All rights reserved. -// bynotes.com - -#import - -enum { - kOAProblemSignatureMethodRejected = 0, - kOAProblemParameterAbsent, - kOAProblemVersionRejected, - kOAProblemConsumerKeyUnknown, - kOAProblemTokenRejected, - kOAProblemSignatureInvalid, - kOAProblemNonceUsed, - kOAProblemTimestampRefused, - kOAProblemTokenExpired, - kOAProblemTokenNotRenewable -}; - -@interface OAProblem : NSObject { - const NSString *problem; -} - -@property (readonly) const NSString *problem; - -- (id)initWithProblem:(const NSString *)aProblem; -- (id)initWithResponseBody:(const NSString *)response; - -- (BOOL)isEqualToProblem:(OAProblem *)aProblem; -- (BOOL)isEqualToString:(const NSString *)aProblem; -- (BOOL)isEqualTo:(id)aProblem; -- (int)code; - -+ (OAProblem *)problemWithResponseBody:(const NSString *)response; - -+ (const NSArray *)validProblems; - -+ (OAProblem *)SignatureMethodRejected; -+ (OAProblem *)ParameterAbsent; -+ (OAProblem *)VersionRejected; -+ (OAProblem *)ConsumerKeyUnknown; -+ (OAProblem *)TokenRejected; -+ (OAProblem *)SignatureInvalid; -+ (OAProblem *)NonceUsed; -+ (OAProblem *)TimestampRefused; -+ (OAProblem *)TokenExpired; -+ (OAProblem *)TokenNotRenewable; - -@end diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.m b/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.m deleted file mode 100755 index 7a885a3c..00000000 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAProblem.m +++ /dev/null @@ -1,165 +0,0 @@ -// -// OAProblem.m -// OAuthConsumer -// -// Created by Alberto García Hierro on 03/09/08. -// Copyright 2008 Alberto García Hierro. All rights reserved. -// bynotes.com - -#import "OAProblem.h" - -const NSString *signature_method_rejected = @"signature_method_rejected"; -const NSString *parameter_absent = @"parameter_absent"; -const NSString *version_rejected = @"version_rejected"; -const NSString *consumer_key_unknown = @"consumer_key_unknown"; -const NSString *token_rejected = @"token_rejected"; -const NSString *signature_invalid = @"signature_invalid"; -const NSString *nonce_used = @"nonce_used"; -const NSString *timestamp_refused = @"timestamp_refused"; -const NSString *token_expired = @"token_expired"; -const NSString *token_not_renewable = @"token_not_renewable"; - -@implementation OAProblem - -@synthesize problem; - -- (id)initWithPointer:(const NSString *) aPointer -{ - [super init]; - problem = aPointer; - return self; -} - -- (id)initWithProblem:(const NSString *) aProblem -{ - NSUInteger idx = [[OAProblem validProblems] indexOfObject:aProblem]; - if (idx == NSNotFound) { - return nil; - } - - return [self initWithPointer: [[OAProblem validProblems] objectAtIndex:idx]]; -} - -- (id)initWithResponseBody:(const NSString *) response -{ - NSArray *fields = [response componentsSeparatedByString:@"&"]; - for (NSString *field in fields) { - if ([field hasPrefix:@"oauth_problem="]) { - NSString *value = [[field componentsSeparatedByString:@"="] objectAtIndex:1]; - return [self initWithProblem:value]; - } - } - - return nil; -} - -+ (OAProblem *)problemWithResponseBody:(const NSString *) response -{ - return [[[OAProblem alloc] initWithResponseBody:response] autorelease]; -} - -+ (const NSArray *)validProblems -{ - static NSArray *array; - if (!array) { - array = [[NSArray alloc] initWithObjects:signature_method_rejected, - parameter_absent, - version_rejected, - consumer_key_unknown, - token_rejected, - signature_invalid, - nonce_used, - timestamp_refused, - token_expired, - token_not_renewable, - nil]; - } - - return array; -} - -- (BOOL)isEqualToProblem:(OAProblem *) aProblem -{ - return [problem isEqualToString:(NSString *)aProblem->problem]; -} - -- (BOOL)isEqualToString:(const NSString *) aProblem -{ - return [problem isEqualToString:(NSString *)aProblem]; -} - -- (BOOL)isEqualTo:(id) aProblem -{ - if ([aProblem isKindOfClass:[NSString class]]) { - return [self isEqualToString:aProblem]; - } - - if ([aProblem isKindOfClass:[OAProblem class]]) { - return [self isEqualToProblem:aProblem]; - } - - return NO; -} - -- (int)code { - return [[[self class] validProblems] indexOfObject:problem]; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"OAuth Problem: %@", (NSString *)problem]; -} - -#pragma mark class_methods - -+ (OAProblem *)SignatureMethodRejected -{ - return [[[OAProblem alloc] initWithPointer:signature_method_rejected] autorelease]; -} - -+ (OAProblem *)ParameterAbsent -{ - return [[[OAProblem alloc] initWithPointer:parameter_absent] autorelease]; -} - -+ (OAProblem *)VersionRejected -{ - return [[[OAProblem alloc] initWithPointer:version_rejected] autorelease]; -} - -+ (OAProblem *)ConsumerKeyUnknown -{ - return [[[OAProblem alloc] initWithPointer:consumer_key_unknown] autorelease]; -} - -+ (OAProblem *)TokenRejected -{ - return [[[OAProblem alloc] initWithPointer:token_rejected] autorelease]; -} - -+ (OAProblem *)SignatureInvalid -{ - return [[[OAProblem alloc] initWithPointer:signature_invalid] autorelease]; -} - -+ (OAProblem *)NonceUsed -{ - return [[[OAProblem alloc] initWithPointer:nonce_used] autorelease]; -} - -+ (OAProblem *)TimestampRefused -{ - return [[[OAProblem alloc] initWithPointer:timestamp_refused] autorelease]; -} - -+ (OAProblem *)TokenExpired -{ - return [[[OAProblem alloc] initWithPointer:token_expired] autorelease]; -} - -+ (OAProblem *)TokenNotRenewable -{ - return [[[OAProblem alloc] initWithPointer:token_not_renewable] autorelease]; -} - -@end diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index e7f8ed7d..abc31ec1 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -59,7 +59,6 @@ // Delicious - https://developer.apps.yahoo.com/projects #define SHKDeliciousConsumerKey @"" #define SHKDeliciousSecretKey @"" -#define SHKDeliciousCallbackUrl @"" // Facebook - http://www.facebook.com/developers #define SHKFacebookKey @"" diff --git a/Classes/ShareKit/UI/SHKNavController.h b/Classes/ShareKit/UI/SHKNavController.h deleted file mode 100644 index 4413e6bd..00000000 --- a/Classes/ShareKit/UI/SHKNavController.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// SHKNavController.h -// ShareKit -// -// Created by Nathan Weiner on 6/28/10. - -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// - -#import - - -@interface SHKNavController : UINavigationController -{ - -} - -@end diff --git a/Classes/ShareKit/UI/SHKNavController.m b/Classes/ShareKit/UI/SHKNavController.m deleted file mode 100644 index 69ece22d..00000000 --- a/Classes/ShareKit/UI/SHKNavController.m +++ /dev/null @@ -1,38 +0,0 @@ - // -// SHKNavController.m -// ShareKit -// -// Created by Nathan Weiner on 6/28/10. - -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// - -#import "SHKNavController.h" - - -@implementation SHKNavController - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation -{ - return YES; -} - -@end From 3b18089ea49cd5a95ed4e07c28c74d808e5577bf Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Tue, 13 Jul 2010 13:21:31 -0700 Subject: [PATCH 12/50] - Fixed logout on device - Fixed facebook logout - Added additional comments for setting up twitter - Added sanity check to catch pin based auth with twitter - Version 0.1.6 - release going to website --- Classes/Example/RootViewController.m | 8 ++- Classes/Example/ShareKitAppDelegate.m | 1 + .../Core/Base Sharer Classes/SHKOAuthSharer.m | 19 +++--- .../Core/Base Sharer Classes/SHKSharer.h | 2 +- .../Core/Base Sharer Classes/SHKSharer.m | 11 ++++ Classes/ShareKit/Core/SHK.h | 5 +- Classes/ShareKit/Core/SHK.m | 33 ++++------- Classes/ShareKit/SHKConfig.h | 59 +++++++++---------- .../Sharers/Services/Facebook/SHKFacebook.m | 8 +++ Classes/ShareKit/UI/SHKOAuthView.m | 9 ++- 10 files changed, 88 insertions(+), 67 deletions(-) diff --git a/Classes/Example/RootViewController.m b/Classes/Example/RootViewController.m index afbf2be1..9672be81 100644 --- a/Classes/Example/RootViewController.m +++ b/Classes/Example/RootViewController.m @@ -28,7 +28,7 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Customize the number of rows in the table view. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return 4; + return 4;//5; } @@ -60,6 +60,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.textLabel.text = @"Sharing a File"; break; + //case 4: + // cell.textLabel.text = @"Logout of All Services"; + // break; } return cell; @@ -89,6 +92,9 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self.navigationController pushViewController:[[[ExampleShareFile alloc] initWithNibName:nil bundle:nil] autorelease] animated:YES]; break; + //case 4: + // [SHK logoutOfAll]; + // break; } } diff --git a/Classes/Example/ShareKitAppDelegate.m b/Classes/Example/ShareKitAppDelegate.m index c9c6a0bc..a5329d45 100644 --- a/Classes/Example/ShareKitAppDelegate.m +++ b/Classes/Example/ShareKitAppDelegate.m @@ -38,6 +38,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( - (void)testOffline { [SHK flushOfflineQueue]; + [SHK logoutOfAll]; } - (void)applicationWillTerminate:(UIApplication *)application diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m index 3cc07392..f19f3493 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m @@ -262,17 +262,16 @@ - (void)storeAccessToken + (void)deleteStoredAccessToken { - [SHK setAuthValue:nil - forKey:@"accessKey" - forSharer:[self sharerId]]; - - [SHK setAuthValue:nil - forKey:@"accessSecret" - forSharer:[self sharerId]]; + NSString *sharerId = [self sharerId]; - [SHK setAuthValue:nil - forKey:@"sessionHandle" - forSharer:[self sharerId]]; + [SHK removeAuthValueForKey:@"accessKey" forSharer:sharerId]; + [SHK removeAuthValueForKey:@"accessSecret" forSharer:sharerId]; + [SHK removeAuthValueForKey:@"sessionHandle" forSharer:sharerId]; +} + ++ (void)logout +{ + [self deleteStoredAccessToken]; } - (BOOL)restoreAccessToken diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h index 424b432e..02063467 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h @@ -144,7 +144,7 @@ typedef enum - (NSString *)authorizationFormCaption; + (NSArray *)authorizationFormFields; + (NSString *)authorizationFormCaption; - ++ (void)logout; #pragma mark - #pragma mark API Implementation diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m index c5616170..38d9e013 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m @@ -422,6 +422,17 @@ + (NSString *)authorizationFormCaption return nil; } ++ (void)logout +{ + NSString *sharerId = [self sharerId]; + NSArray *authFields = [self authorizationFormFields]; + if (authFields != nil) + { + for(SHKFormFieldSettings *field in authFields) + [SHK removeAuthValueForKey:field.key forSharer:sharerId]; + } +} + diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index 9988083f..dadaca1a 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -1,4 +1,4 @@ -// +å// // SHK.h // ShareKit // @@ -25,7 +25,7 @@ // // -#define SHK_VERSION @"0.1.0" +#define SHK_VERSION @"0.1.6" #import @@ -96,6 +96,7 @@ + (NSString *)getAuthValueForKey:(NSString *)key forSharer:(NSString *)sharerId; + (void)setAuthValue:(NSString *)value forKey:(NSString *)key forSharer:(NSString *)sharerId; ++ (void)removeAuthValueForKey:(NSString *)key forSharer:(NSString *)sharerId; + (void)logoutOfAll; + (void)logoutOfService:(NSString *)sharerId; diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m index c95d51d1..1545f9fd 100644 --- a/Classes/ShareKit/Core/SHK.m +++ b/Classes/ShareKit/Core/SHK.m @@ -327,6 +327,18 @@ + (void)setAuthValue:(NSString *)value forKey:(NSString *)key forSharer:(NSStrin #endif } ++ (void)removeAuthValueForKey:(NSString *)key forSharer:(NSString *)sharerId +{ +#if TARGET_IPHONE_SIMULATOR + // Using NSUserDefaults for storage is very insecure, but because Keychain only exists on a device + // we use NSUserDefaults when running on the simulator to store objects. This allows you to still test + // in the simulator. You should NOT modify in a way that does not use keychain when actually deployed to a device. + [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:@"%@%@%@",SHK_AUTH_PREFIX,sharerId,key]]; +#else + [SFHFKeychainUtils deleteItemForUsername:key andServiceName:[NSString stringWithFormat:@"%@%@",SHK_AUTH_PREFIX,sharerId] error:nil]; +#endif +} + + (void)logoutOfAll { NSArray *sharers = [[SHK sharersDictionary] objectForKey:@"services"]; @@ -336,26 +348,7 @@ + (void)logoutOfAll + (void)logoutOfService:(NSString *)sharerId { - // TODO - can we just clear the keychain of a specific service name in one go rather than enumerating through each auth value? - - SHKSharer *class = (SHKSharer *)NSClassFromString(sharerId); - - // oauth web service - if ([class respondsToSelector:@selector(deleteStoredAccessToken)]) - [class performSelector:@selector(deleteStoredAccessToken)]; - - // web service - else - { - NSArray *authFields = [class authorizationFormFields]; - if (authFields != nil) - { - for(SHKFormFieldSettings *field in authFields) - [SHK setAuthValue:nil forKey:field.key forSharer:sharerId]; - } - } - - + [NSClassFromString(sharerId) logout]; } diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index abc31ec1..8e291f7e 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -1,32 +1,14 @@ -// -// SHKConfig.h -// ShareKit -// -// Created by Nathan Weiner on 6/23/10. - -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// - - -#error Setup the SHKConfig.h file, then remove this error by commenting it out. + + + + + +// PLEASE SEE INSTALL/CONFIG INSTRUCTIONS: +// http://getsharekit.com/install + + + + // App Description @@ -64,15 +46,28 @@ #define SHKFacebookKey @"" #define SHKFacebookSecret @"" -// Flickr - // Read It Later - http://readitlaterlist.com/api/?shk #define SHKReadItLaterKey @"" // Twitter - http://dev.twitter.com/apps/new +/* + Important Twitter settings to get right: + + Differences between OAuth and xAuth + -- + There are two types of authentication provided for Twitter, OAuth and xAuth. OAuth is the default and will + present a web view to log the user in. xAuth presents a native entry form but requires Twitter to add xAuth to your app (you have to request it from them). + If your app has been approved for xAuth, set SHKTwitterUseXAuth to 1. + + Callback URL (important to get right for OAuth users) + -- + 1. Open your application settings at http://dev.twitter.com/apps/ + 2. 'Application Type' should be set to BROWSER (not client) + 3. 'Callback URL' should match whatever you enter in SHKTwitterCallbackUrl. The callback url doesn't have to be an actual existing url. The user will never get to it because ShareKit intercepts it before the user is redirected. It just needs to match. +*/ #define SHKTwitterConsumerKey @"" #define SHKTwitterSecret @"" -#define SHKTwitterCallbackUrl @"" // HOW-TO: In your Twitter application settings, use the "Callback URL" field. If you do not have this field in the settings, set your application type to 'Browser'. +#define SHKTwitterCallbackUrl @"" // You need to set this if using OAuth, see note above (xAuth users can skip it) #define SHKTwitterUseXAuth 0 // To use xAuth, set to 1 #define SHKTwitterUsername @"" // Enter your app's twitter account if you'd like to ask the user to follow it when logging in. (Only for xAuth) diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 708d75c2..818eb1b4 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -107,6 +107,14 @@ - (void)authFinished:(SHKRequest *)request } ++ (void)logout +{ + FBSession *fbSession = [FBSession sessionForApplication:SHKFacebookKey + secret:SHKFacebookSecret + delegate:[[[self alloc] init] autorelease]]; + [fbSession logout]; +} + #pragma mark - #pragma mark Share API Methods diff --git a/Classes/ShareKit/UI/SHKOAuthView.m b/Classes/ShareKit/UI/SHKOAuthView.m index 4dd2da88..9c67cede 100644 --- a/Classes/ShareKit/UI/SHKOAuthView.m +++ b/Classes/ShareKit/UI/SHKOAuthView.m @@ -54,6 +54,7 @@ - (id)initWithURL:(NSURL *)authorizeURL delegate:(id)d self.webView = [[UIWebView alloc] initWithFrame:CGRectZero]; webView.delegate = self; webView.scalesPageToFit = YES; + webView.dataDetectorTypes = UIDataDetectorTypeNone; [webView release]; [webView loadRequest:[NSURLRequest requestWithURL:authorizeURL]]; @@ -78,6 +79,8 @@ - (void)viewDidDisappear:(BOOL)animated - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { + NSLog(@"url %@", request.URL); + if ([request.URL.absoluteString rangeOfString:[delegate authorizeCallbackURL].absoluteString].location != NSNotFound) { // Get query @@ -109,9 +112,13 @@ - (void)webViewDidStartLoad:(UIWebView *)webView [self startSpinner]; } -- (void)webViewDidFinishLoad:(UIWebView *)webView +- (void)webViewDidFinishLoad:(UIWebView *)aWebView { [self stopSpinner]; + + // Extra sanity check for Twitter OAuth users to make sure they are using BROWSER with a callback instead of pin based auth + if ([webView.request.URL.host isEqualToString:@"twitter.com"] && [webView stringByEvaluatingJavaScriptFromString:@"document.getElementById('oauth_pin').innerHTML"].length) + [delegate tokenAuthorizeView:self didFinishWithSuccess:NO queryParams:nil error:[SHK error:@"Your SHKTwitter config is incorrect. You must set your application type to Browser and define a callback url. See SHKConfig.h for more details"]]; } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error From 1a6b59cb0558061d4ef0263b476828899a09a835 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Tue, 13 Jul 2010 13:26:02 -0700 Subject: [PATCH 13/50] fixed test case in example project --- Classes/Example/ShareKitAppDelegate.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Classes/Example/ShareKitAppDelegate.m b/Classes/Example/ShareKitAppDelegate.m index a5329d45..c9c6a0bc 100644 --- a/Classes/Example/ShareKitAppDelegate.m +++ b/Classes/Example/ShareKitAppDelegate.m @@ -38,7 +38,6 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( - (void)testOffline { [SHK flushOfflineQueue]; - [SHK logoutOfAll]; } - (void)applicationWillTerminate:(UIApplication *)application From 5a66c8538a8df45aefc93324090e6feb26d8613a Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Tue, 13 Jul 2010 13:39:45 -0700 Subject: [PATCH 14/50] Cleanup --- Classes/ShareKit/Core/SHK.h | 2 +- Classes/ShareKit/UI/SHKOAuthView.m | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index dadaca1a..a55c2a6c 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -1,4 +1,4 @@ -å// +// // SHK.h // ShareKit // diff --git a/Classes/ShareKit/UI/SHKOAuthView.m b/Classes/ShareKit/UI/SHKOAuthView.m index 9c67cede..7b735ca0 100644 --- a/Classes/ShareKit/UI/SHKOAuthView.m +++ b/Classes/ShareKit/UI/SHKOAuthView.m @@ -78,9 +78,7 @@ - (void)viewDidDisappear:(BOOL)animated - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType -{ - NSLog(@"url %@", request.URL); - +{ if ([request.URL.absoluteString rangeOfString:[delegate authorizeCallbackURL].absoluteString].location != NSNotFound) { // Get query From 38bc1f8cab992d614e797d67897af93c144b6caf Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 19 Jul 2010 23:53:17 +0200 Subject: [PATCH 15/50] full localization support for ShareKit. Added german. You can add your own language by simply adding your lang in ShareKit.bundle. You have to include ShareKit.bundle now in your project --- Classes/Example/RootViewController.m | 10 ++--- .../Core/Base Sharer Classes/SHKOAuthSharer.m | 26 ++++++------ .../Core/Base Sharer Classes/SHKSharer.m | 38 ++++++++--------- Classes/ShareKit/Core/SHK.h | 3 +- Classes/ShareKit/Core/SHK.m | 12 ++++++ .../ShareKit/Sharers/Actions/Copy/SHKCopy.m | 4 +- .../ShareKit/Sharers/Actions/Email/SHKMail.m | 2 +- .../Actions/Open in Safari/SHKSafari.m | 2 +- .../Sharers/Services/Delicious/SHKDelicious.m | 12 +++--- .../Sharers/Services/Facebook/SHKFacebook.m | 2 +- .../Services/Google Reader/SHKGoogleReader.m | 24 +++++------ .../Services/Instapaper/SHKInstapaper.m | 18 ++++---- .../Sharers/Services/Pinboard/SHKPinboard.m | 16 +++---- .../Services/Read It Later/SHKReadItLater.m | 12 +++--- .../Sharers/Services/Tumblr/SHKTumblr.m | 40 +++++++++--------- .../Sharers/Services/Twitter/SHKTwitter.m | 14 +++--- .../Sharers/Services/Twitter/SHKTwitterForm.m | 14 +++--- Classes/ShareKit/UI/SHKActionSheet.m | 6 +-- Classes/ShareKit/UI/SHKShareMenu.m | 10 ++--- ShareKit.bundle/de.lproj/Localizable.strings | Bin 0 -> 8606 bytes ShareKit.bundle/en.lproj/Localizable.strings | Bin 0 -> 8582 bytes ShareKit.xcodeproj/project.pbxproj | 4 ++ 22 files changed, 142 insertions(+), 127 deletions(-) create mode 100644 ShareKit.bundle/de.lproj/Localizable.strings create mode 100644 ShareKit.bundle/en.lproj/Localizable.strings diff --git a/Classes/Example/RootViewController.m b/Classes/Example/RootViewController.m index 9672be81..034de581 100644 --- a/Classes/Example/RootViewController.m +++ b/Classes/Example/RootViewController.m @@ -45,23 +45,23 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N switch (indexPath.row) { case 0: - cell.textLabel.text = @"Sharing a Link"; + cell.textLabel.text = SKLocalizedString(@"Sharing a Link"); break; case 1: - cell.textLabel.text = @"Sharing an Image"; + cell.textLabel.text = SKLocalizedString(@"Sharing an Image"); break; case 2: - cell.textLabel.text = @"Sharing Text"; + cell.textLabel.text = SKLocalizedString(@"Sharing Text"); break; case 3: - cell.textLabel.text = @"Sharing a File"; + cell.textLabel.text = SKLocalizedString(@"Sharing a File"); break; //case 4: - // cell.textLabel.text = @"Logout of All Services"; + // cell.textLabel.text = SKLocalizedString(@"Logout of All Services"); // break; } diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m index f19f3493..d27c4ea3 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m @@ -76,7 +76,7 @@ - (void)promptAuthorization - (void)tokenRequest { - [[SHKActivityIndicator currentIndicator] displayActivity:@"Connecting..."]; + [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Connecting...")]; OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:requestURL consumer:consumer @@ -121,17 +121,17 @@ - (void)tokenRequestTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData * else // TODO - better error handling here - [self tokenRequestTicket:ticket didFailWithError:[SHK error:@"There was a problem requesting authorization from %@", [self sharerTitle]]]; + [self tokenRequestTicket:ticket didFailWithError:[SHK error:SKLocalizedString(@"There was a problem requesting authorization from %@"), [self sharerTitle]]]; } - (void)tokenRequestTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error { [[SHKActivityIndicator currentIndicator] hide]; - [[[[UIAlertView alloc] initWithTitle:@"Request Error" - message:error!=nil?[error localizedDescription]:@"There was an error while sharing" + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Request Error") + message:error!=nil?[error localizedDescription]:SKLocalizedString(@"There was an error while sharing") delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } @@ -153,10 +153,10 @@ - (void)tokenAuthorizeView:(SHKOAuthView *)authView didFinishWithSuccess:(BOOL)s if (!success) { - [[[[UIAlertView alloc] initWithTitle:@"Authorize Error" - message:error!=nil?[error localizedDescription]:@"There was an error while authorizing" + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Authorize Error") + message:error!=nil?[error localizedDescription]:SKLocalizedString(@"There was an error while authorizing") delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } @@ -184,7 +184,7 @@ - (void)tokenAccess - (void)tokenAccess:(BOOL)refresh { if (!refresh) - [[SHKActivityIndicator currentIndicator] displayActivity:@"Authenticating..."]; + [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Authenticating...")]; OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:accessURL consumer:consumer @@ -231,17 +231,17 @@ - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *) else // TODO - better error handling here - [self tokenAccessTicket:ticket didFailWithError:[SHK error:@"There was a problem requesting access from %@", [self sharerTitle]]]; + [self tokenAccessTicket:ticket didFailWithError:[SHK error:SKLocalizedString(@"There was a problem requesting access from %@"), [self sharerTitle]]]; } - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error { [[SHKActivityIndicator currentIndicator] hide]; - [[[[UIAlertView alloc] initWithTitle:@"Access Error" - message:error!=nil?[error localizedDescription]:@"There was an error while sharing" + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Access Error") + message:error!=nil?[error localizedDescription]:SKLocalizedString(@"There was an error while sharing") delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m index 38d9e013..de05319a 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m @@ -322,10 +322,10 @@ - (void)promptAuthorization { if (!quiet) { - [[[[UIAlertView alloc] initWithTitle:@"Offline" - message:[NSString stringWithFormat:@"You must be online to login to %@", [self sharerTitle]] + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Offline") + message:[NSString stringWithFormat:SKLocalizedString(@"You must be online to login to %@"), [self sharerTitle]] delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } return; @@ -349,7 +349,7 @@ - (void)setShouldAutoShare:(BOOL)b - (void)authorizationFormShow { // Create the form - SHKCustomFormController *form = [[SHKCustomFormController alloc] initWithStyle:UITableViewStyleGrouped title:@"Login" rightButtonTitle:@"Login"]; + SHKCustomFormController *form = [[SHKCustomFormController alloc] initWithStyle:UITableViewStyleGrouped title:SKLocalizedString(@"Login") rightButtonTitle:SKLocalizedString(@"Login")]; [form addSection:[self authorizationFormFields] header:nil footer:[self authorizationFormCaption]]; form.delegate = self; form.validateSelector = @selector(authorizationFormValidate:); @@ -407,8 +407,8 @@ - (NSArray *)authorizationFormFields + (NSArray *)authorizationFormFields { return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Username" key:@"username" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:@"Password" key:@"password" type:SHKFormFieldTypePassword start:nil], + [SHKFormFieldSettings label:SKLocalizedString(@"Username") key:@"username" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:SKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], nil]; } @@ -450,7 +450,7 @@ - (void)show { SHKCustomFormController *rootView = [[SHKCustomFormController alloc] initWithStyle:UITableViewStyleGrouped title:nil - rightButtonTitle:[NSString stringWithFormat:@"Send to %@", [[self class] sharerTitle]] + rightButtonTitle:[NSString stringWithFormat:SKLocalizedString(@"Send to %@"), [[self class] sharerTitle]] ]; [rootView addSection:[self shareFormFieldsForType:item.shareType] header:nil footer:item.URL!=nil?item.URL.absoluteString:nil]; @@ -458,10 +458,10 @@ - (void)show { [rootView addSection: [NSArray arrayWithObject: - [SHKFormFieldSettings label:@"Auto Share" key:@"autoShare" type:SHKFormFieldTypeSwitch start:([self shouldAutoShare]?SHKFormFieldSwitchOn:SHKFormFieldSwitchOff)] + [SHKFormFieldSettings label:SKLocalizedString(@"Auto Share") key:@"autoShare" type:SHKFormFieldTypeSwitch start:([self shouldAutoShare]?SHKFormFieldSwitchOn:SHKFormFieldSwitchOff)] ] header:nil - footer:@"Enable auto share to skip this step in the future."]; + footer:SKLocalizedString(@"Enable auto share to skip this step in the future.")]; } rootView.delegate = self; @@ -484,7 +484,7 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Title" key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], nil]; return nil; @@ -577,10 +577,10 @@ - (BOOL)tryToSend else if (!quiet) { - [[[[UIAlertView alloc] initWithTitle:@"Offline" - message:[NSString stringWithFormat:@"You must be online in order to share with %@", [self sharerTitle]] + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Offline") + message:[NSString stringWithFormat:SKLocalizedString(@"You must be online in order to share with %@"), [self sharerTitle]] delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; return YES; @@ -609,13 +609,13 @@ - (BOOL)send - (void)sharerStartedSending:(SHKSharer *)sharer { if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:[NSString stringWithFormat:@"Saving to %@", [[self class] sharerTitle]]]; + [[SHKActivityIndicator currentIndicator] displayActivity:[NSString stringWithFormat:SKLocalizedString(@"Saving to %@"), [[self class] sharerTitle]]]; } - (void)sharerFinishedSending:(SHKSharer *)sharer { if (!quiet) - [[SHKActivityIndicator currentIndicator] displayCompleted:@"Saved!"]; + [[SHKActivityIndicator currentIndicator] displayCompleted:SKLocalizedString(@"Saved!")]; } - (void)sharer:(SHKSharer *)sharer failedWithError:(NSError *)error shouldRelogin:(BOOL)shouldRelogin @@ -624,10 +624,10 @@ - (void)sharer:(SHKSharer *)sharer failedWithError:(NSError *)error shouldRelogi { [[SHKActivityIndicator currentIndicator] hide]; - [[[[UIAlertView alloc] initWithTitle:@"Error" - message:sharer.lastError!=nil?[sharer.lastError localizedDescription]:@"There was an error while sharing" + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Error") + message:sharer.lastError!=nil?[sharer.lastError localizedDescription]:SKLocalizedString(@"There was an error while sharing") delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; if (shouldRelogin) @@ -688,7 +688,7 @@ - (void)sendDidFinish - (void)sendDidFailShouldRelogin { - [self sendDidFailWithError:[SHK error:@"Could not authenticate you. Please relogin."] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"Could not authenticate you. Please relogin.")] shouldRelogin:YES]; } - (void)sendDidFailWithError:(NSError *)error diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index a55c2a6c..90cbf41a 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -27,7 +27,6 @@ #define SHK_VERSION @"0.1.6" - #import #import "SHKConfig.h" #import "SHKItem.h" @@ -124,4 +123,4 @@ NSString * SHKEncode(NSString * value); NSString * SHKEncodeURL(NSURL * value); - +NSString * SKLocalizedString(NSString* key); diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m index 1545f9fd..e6fcc3b0 100644 --- a/Classes/ShareKit/Core/SHK.m +++ b/Classes/ShareKit/Core/SHK.m @@ -515,3 +515,15 @@ + (BOOL)connected [result autorelease]; return result; } + + +NSString* SKLocalizedString(NSString* key) { + static NSBundle* bundle = nil; + if (!bundle) { + NSString* path = [[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent:@"ShareKit.bundle"]; + bundle = [[NSBundle bundleWithPath:path] retain]; + } + + return [bundle localizedStringForKey:key value:key table:nil]; +} \ No newline at end of file diff --git a/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m b/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m index 15b92a0f..5daf879e 100644 --- a/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m +++ b/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m @@ -35,7 +35,7 @@ @implementation SHKCopy + (NSString *)sharerTitle { - return @"Copy"; + return SKLocalizedString(@"Copy"); } + (BOOL)canShareURL @@ -80,7 +80,7 @@ - (BOOL)send [[UIPasteboard generalPasteboard] setImage:item.image]; // Notify user - [[SHKActivityIndicator currentIndicator] displayCompleted:@"Copied!"]; + [[SHKActivityIndicator currentIndicator] displayCompleted:SKLocalizedString(@"Copied!")]; return YES; } diff --git a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m index b4117e51..53d23bb2 100644 --- a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m +++ b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m @@ -138,7 +138,7 @@ + (id)shareText:(NSString *)text + (id)shareFile:(NSData *)file filename:(NSString *)filename mimeType:(NSString *)mimeType title:(NSString *)title { - return [self mail:[NSString stringWithFormat:@"Attached: %@", title] + return [self mail:[NSString stringWithFormat:SKLocalizedString(@"Attached: %@"), title] subject:filename to:nil cc:nil bcc:nil attachment:file attachmentMimeType:mimeType attachmentFileName:filename]; } diff --git a/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m index 2e269d44..7ef4f239 100644 --- a/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m +++ b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m @@ -37,7 +37,7 @@ @implementation SHKSafari + (NSString *)sharerTitle { - return @"Open in Safari"; + return SKLocalizedString(@"Open in Safari"); } + (BOOL)canShareURL diff --git a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m index 832b122b..2f5106a1 100644 --- a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m +++ b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m @@ -100,7 +100,7 @@ - (BOOL)handleResponse:(SHKRequest *)aRequest { NSString *response = [aRequest getResult]; - if ([response isEqualToString:@"401 Forbidden"]) + if ([response isEqualToString:SKLocalizedString(@"401 Forbidden")]) { [self sendDidFailShouldRelogin]; return NO; @@ -117,10 +117,10 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Title" key:@"title" type:SHKFormFieldTypeText start:item.title], - [SHKFormFieldSettings label:@"Tags" key:@"tags" type:SHKFormFieldTypeText start:item.tags], - [SHKFormFieldSettings label:@"Notes" key:@"text" type:SHKFormFieldTypeText start:item.text], - [SHKFormFieldSettings label:@"Shared" key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + [SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:SKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], + [SHKFormFieldSettings label:SKLocalizedString(@"Notes") key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:SKLocalizedString(@"Shared") key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], nil]; return nil; @@ -209,7 +209,7 @@ - (void)sendTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data } else - error = [SHK error:@"There was a problem saving to Delicious"]; + error = [SHK error:SKLocalizedString(@"There was a problem saving to Delicious.")]; [self sendTicket:ticket didFailWithError:error]; } diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 818eb1b4..40ce4112 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -126,7 +126,7 @@ - (BOOL)send FBStreamDialog* dialog = [[[FBStreamDialog alloc] init] autorelease]; dialog.delegate = self; - dialog.userMessagePrompt = @"Enter your message:"; + dialog.userMessagePrompt = SKLocalizedString(@"Enter your message:"); dialog.attachment = [NSString stringWithFormat: @"{\ \"name\":\"%@\",\ diff --git a/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m index 1b84ae3d..467c86ab 100644 --- a/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m +++ b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m @@ -72,14 +72,14 @@ + (BOOL)canShareURL + (NSString *)authorizationFormCaption { - return @"Create a free account at Google.com/reader"; + return SKLocalizedString(@"Create a free account at Google.com/reader"); } + (NSArray *)authorizationFormFields { return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Email" key:@"email" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:@"Password" key:@"password" type:SHKFormFieldTypePassword start:nil], + [SHKFormFieldSettings label:SKLocalizedString(@"Email") key:@"email" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:SKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], nil]; } @@ -87,7 +87,7 @@ - (void)authorizationFormValidate:(SHKFormController *)form { // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -155,15 +155,15 @@ - (void)authFinished:(SHKRequest *)aRequest NSString *message = nil; if (error != nil) - message = [error isEqualToString:@"BadAuthentication"] ? @"Incorrect username and password" : error; + message = [error isEqualToString:@"BadAuthentication"] ? SKLocalizedString(@"Incorrect username and password") : error; if (message == nil) // TODO - Could use some clearer message here. - message = @"There was an error logging into Google Reader"; + message = SKLocalizedString(@"There was an error logging into Google Reader"); - [[[[UIAlertView alloc] initWithTitle:@"Login Error" + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Login Error") message:message delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } } @@ -176,8 +176,8 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Note" key:@"text" type:SHKFormFieldTypeText start:item.text], - [SHKFormFieldSettings label:@"Public" key:@"share" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + [SHKFormFieldSettings label:SKLocalizedString(@"Note") key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:SKLocalizedString(@"Public") key:@"share" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], nil]; return nil; @@ -262,7 +262,7 @@ - (void)tokenFinished:(SHKRequest *)aRequest [self sendWithToken:[request getResult]]; else - [self sendDidFailWithError:[SHK error:@"There was a problem authenticating your account."]]; // TODO better error handling/message + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a problem authenticating your account.")]]; // TODO better error handling/message } - (void)sendWithToken:(NSString *)token @@ -294,7 +294,7 @@ - (void)sendFinished:(SHKRequest *)aRequest [self sendDidFinish]; else - [self sendDidFailWithError:[SHK error:@"There was a problem saving your note."]]; // TODO better error handling/message + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a problem saving your note.")]]; // TODO better error handling/message } diff --git a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m index 94ca9a79..52c4d74f 100755 --- a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m +++ b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m @@ -57,14 +57,14 @@ + (BOOL)canShare + (NSString *)authorizationFormCaption { - return @"Create a free account at Instapaper.com"; + return SKLocalizedString(@"Create a free account at Instapaper.com"); } - (void)authorizationFormValidate:(SHKFormController *)form { // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -95,14 +95,14 @@ - (void)authFinished:(SHKRequest *)aRequest else { NSString *errorMessage = nil; if (aRequest.response.statusCode == 403) - errorMessage = @"Sorry, Instapaper did not accept your credentials. Please try again."; + errorMessage = SKLocalizedString(@"Sorry, Instapaper did not accept your credentials. Please try again."); else - errorMessage = @"Sorry, Instapaper encountered an error. Please try again."; + errorMessage = SKLocalizedString(@"Sorry, Instapaper encountered an error. Please try again."); - [[[[UIAlertView alloc] initWithTitle:@"Login Error" + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Login Error") message:errorMessage delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } } @@ -148,15 +148,15 @@ - (void)sendFinished:(SHKRequest *)aRequest { if (!aRequest.success) { if (aRequest.response.statusCode == 403) { - [self sendDidFailWithError:[SHK error:@"Sorry, Instapaper did not accept your credentials. Please try again."] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"Sorry, Instapaper did not accept your credentials. Please try again.")] shouldRelogin:YES]; return; } else if (aRequest.response.statusCode == 500) { - [self sendDidFailWithError:[SHK error:@"The service encountered an error. Please try again later."]]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"The service encountered an error. Please try again later.")]]; return; } - [self sendDidFailWithError:[SHK error:@"There was a problem saving to Instapaper."]]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a problem saving to Instapaper.")]]; return; } diff --git a/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m index 04deeaf7..f6edf304 100644 --- a/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m +++ b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m @@ -51,14 +51,14 @@ + (BOOL)canShareURL + (NSString *)authorizationFormCaption { - return @"Create an account at http://pinboard.in"; + return SKLocalizedString(@"Create an account at http://pinboard.in"); } - (void)authorizationFormValidate:(SHKFormController *)form { // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -82,7 +82,7 @@ - (BOOL)handleResponse:(SHKRequest *)aRequest { NSString *response = [aRequest getResult]; - if ([response isEqualToString:@"401 Forbidden"]) + if ([response isEqualToString:SKLocalizedString(@"401 Forbidden")]) { [self sendDidFailShouldRelogin]; return NO; @@ -110,10 +110,10 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Title" key:@"title" type:SHKFormFieldTypeText start:item.title], - [SHKFormFieldSettings label:@"Tags" key:@"tags" type:SHKFormFieldTypeText start:item.tags], - [SHKFormFieldSettings label:@"Notes" key:@"text" type:SHKFormFieldTypeText start:item.text], - [SHKFormFieldSettings label:@"Shared" key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + [SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:SKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], + [SHKFormFieldSettings label:SKLocalizedString(@"Notes") key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:SKLocalizedString(@"Shared") key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], nil]; return nil; @@ -167,7 +167,7 @@ - (void)sendFinished:(SHKRequest *)aRequest } } - [self sendDidFailWithError:[SHK error:@"There was an error saving to Pinboard"]]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was an error saving to Pinboard")]]; } @end diff --git a/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m b/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m index ca954a2a..1110b7fc 100644 --- a/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m +++ b/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m @@ -63,14 +63,14 @@ - (BOOL)shouldAutoShare + (NSString *)authorizationFormCaption { - return @"Create a free account at Readitlaterlist.com"; + return SKLocalizedString(@"Create a free account at Readitlaterlist.com"); } - (void)authorizationFormValidate:(SHKFormController *)form { // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -102,10 +102,10 @@ - (void)authFinished:(SHKRequest *)aRequest else { - [[[[UIAlertView alloc] initWithTitle:@"Login Error" + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Login Error") message:[request.headers objectForKey:@"X-Error"] delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } } @@ -119,8 +119,8 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Title" key:@"title" type:SHKFormFieldTypeText start:item.title], - [SHKFormFieldSettings label:@"Tags" key:@"tags" type:SHKFormFieldTypeText start:item.tags], + [SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:SKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], nil]; return nil; diff --git a/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m index ece8c120..4f8d355b 100644 --- a/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m +++ b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m @@ -59,13 +59,13 @@ - (BOOL)shouldAutoShare{ #pragma mark Authorization - (NSString *)authorizationFormCaption{ - return @"Set up a free account at http://tumblr.com"; + return SKLocalizedString(@"Set up a free account at http://tumblr.com"); } - (void)authorizationFormValidate:(SHKFormController *)form{ // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:@"Logging In..."]; + [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -94,14 +94,14 @@ - (void)authFinished:(SHKRequest *)aRequest{ else { NSString *errorMessage = nil; if (aRequest.response.statusCode == 403) - errorMessage = @"Invalid email or password."; + errorMessage = SKLocalizedString(@"Invalid email or password."); else - errorMessage = @"The service encountered an error. Please try again later."; + errorMessage = SKLocalizedString(@"The service encountered an error. Please try again later."); - [[[[UIAlertView alloc] initWithTitle:@"Login Error" + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Login Error") message:errorMessage delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } } @@ -110,11 +110,11 @@ - (void)authFinished:(SHKRequest *)aRequest{ #pragma mark Authorize form - (NSArray *)authorizationFormFields{ return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Email" + [SHKFormFieldSettings label:SKLocalizedString(@"Email") key:@"email" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:@"Password" + [SHKFormFieldSettings label:SKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], @@ -126,32 +126,32 @@ - (NSArray *)authorizationFormFields{ - (NSArray *)shareFormFieldsForType:(SHKShareType)type{ NSMutableArray *baseArray = [NSMutableArray arrayWithObjects: - [SHKFormFieldSettings label:@"Tags" + [SHKFormFieldSettings label:SKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], - [SHKFormFieldSettings label:@"Slug" + [SHKFormFieldSettings label:SKLocalizedString(@"Slug") key:@"slug" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:@"Private" + [SHKFormFieldSettings label:SKLocalizedString(@"Private") key:@"private" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], - [SHKFormFieldSettings label:@"Send to Twitter" + [SHKFormFieldSettings label:SKLocalizedString(@"Send to Twitter") key:@"twitter" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], nil ]; if([item shareType] == SHKShareTypeImage){ - [baseArray insertObject:[SHKFormFieldSettings label:@"Caption" + [baseArray insertObject:[SHKFormFieldSettings label:SKLocalizedString(@"Caption") key:@"caption" type:SHKFormFieldTypeText start:nil] atIndex:0]; }else{ - [baseArray insertObject:[SHKFormFieldSettings label:@"Title" + [baseArray insertObject:[SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title] @@ -310,15 +310,15 @@ - (BOOL)send{ - (void)sendFinished:(SHKRequest *)aRequest{ if (!aRequest.success) { if (aRequest.response.statusCode == 403) { - [self sendDidFailWithError:[SHK error:@"Invalid email or password."] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"Invalid email or password.")] shouldRelogin:YES]; return; } else if (aRequest.response.statusCode == 500) { - [self sendDidFailWithError:[SHK error:@"The service encountered an error. Please try again later."]]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"The service encountered an error. Please try again later.")]]; return; } - [self sendDidFailWithError:[SHK error:@"There was a sending your post to Tumblr."]]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a sending your post to Tumblr.")]]; return; } @@ -352,14 +352,14 @@ - (void)finish{ [self sendDidFinish]; }else{ if(response.statusCode == 403) { - [self sendDidFailWithError:[SHK error:@"Invalid email or password."] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"Invalid email or password.")] shouldRelogin:YES]; return; } else if (response.statusCode == 500) { - [self sendDidFailWithError:[SHK error:@"The service encountered an error. Please try again later."]]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"The service encountered an error. Please try again later.")]]; return; } - [self sendDidFailWithError:[SHK error:@"There was a sending your post to Tumblr."]]; + [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a sending your post to Tumblr.")]]; } } diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index b5f49722..5c564e62 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -124,9 +124,9 @@ + (NSArray *)authorizationFormFields return [super authorizationFormFields]; return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:@"Username" key:@"username" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:@"Password" key:@"password" type:SHKFormFieldTypePassword start:nil], - [SHKFormFieldSettings label:[NSString stringWithFormat:@"Follow %@",SHKTwitterUsername] key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], + [SHKFormFieldSettings label:SKLocalizedString(@"Username") key:@"username" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:SKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], + [SHKFormFieldSettings label:[NSString stringWithFormat:SKLocalizedString(@"Follow %@"),SHKTwitterUsername] key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], nil]; } @@ -227,7 +227,7 @@ - (void)sendForm:(SHKTwitterForm *)form - (void)shortenURL { if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:@"Shortening URL..."]; + [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Shortening URL...")]; self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:[NSMutableString stringWithFormat:@"http://api.bit.ly/v3/shorten?login=%@&apikey=%@&longUrl=%@&format=txt", SHKBitLyLogin, @@ -250,10 +250,10 @@ - (void)shortenURLFinished:(SHKRequest *)aRequest if (result == nil || [NSURL URLWithString:result] == nil) { // TODO - better error message - [[[[UIAlertView alloc] initWithTitle:@"Shorten URL Error" - message:@"We could not shorten the URL." + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Shorten URL Error") + message:SKLocalizedString(@"We could not shorten the URL.") delegate:nil - cancelButtonTitle:@"Continue" + cancelButtonTitle:SKLocalizedString(@"Continue") otherButtonTitles:nil] autorelease] show]; [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.title, [item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] forKey:@"status"]; diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m index a6932e71..a64d1cd2 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m @@ -53,7 +53,7 @@ - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil target:self action:@selector(cancel)]; - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Send to Twitter" + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:SKLocalizedString(@"Send to Twitter") style:UIBarButtonItemStyleDone target:self action:@selector(save)]; @@ -186,20 +186,20 @@ - (void)save { if (textView.text.length > (hasAttachment?115:140)) { - [[[[UIAlertView alloc] initWithTitle:@"Message is too long" - message:@"Twitter posts can only be 140 characters in length." + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Message is too long") + message:SKLocalizedString(@"Twitter posts can only be 140 characters in length.") delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; return; } else if (textView.text.length == 0) { - [[[[UIAlertView alloc] initWithTitle:@"Message is empty" - message:@"You must enter a message in order to post." + [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Message is empty") + message:SKLocalizedString(@"You must enter a message in order to post.") delegate:nil - cancelButtonTitle:@"Close" + cancelButtonTitle:SKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; return; } diff --git a/Classes/ShareKit/UI/SHKActionSheet.m b/Classes/ShareKit/UI/SHKActionSheet.m index 6011b72f..6fd6c1bb 100644 --- a/Classes/ShareKit/UI/SHKActionSheet.m +++ b/Classes/ShareKit/UI/SHKActionSheet.m @@ -44,7 +44,7 @@ - (void)dealloc + (SHKActionSheet *)actionSheetForType:(SHKShareType)type { - SHKActionSheet *as = [[SHKActionSheet alloc] initWithTitle:@"Share" + SHKActionSheet *as = [[SHKActionSheet alloc] initWithTitle:SKLocalizedString(@"Share") delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil @@ -65,10 +65,10 @@ + (SHKActionSheet *)actionSheetForType:(SHKShareType)type } // Add More button - [as addButtonWithTitle:@"More..."]; + [as addButtonWithTitle:SKLocalizedString(@"More...")]; // Add Cancel button - [as addButtonWithTitle:@"Cancel"]; + [as addButtonWithTitle:SKLocalizedString(@"Cancel")]; as.cancelButtonIndex = as.numberOfButtons -1; return [as autorelease]; diff --git a/Classes/ShareKit/UI/SHKShareMenu.m b/Classes/ShareKit/UI/SHKShareMenu.m index 4018d599..267f9124 100644 --- a/Classes/ShareKit/UI/SHKShareMenu.m +++ b/Classes/ShareKit/UI/SHKShareMenu.m @@ -52,13 +52,13 @@ - (id)initWithStyle:(UITableViewStyle)style { if (self = [super initWithStyle:style]) { - self.title = @"Share"; + self.title = SKLocalizedString(@"Share"); self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Edit" + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:SKLocalizedString(@"Edit") style:UIBarButtonItemStyleBordered target:self action:@selector(edit)]; @@ -279,10 +279,10 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte if ([[tableData objectAtIndex:section] count]) { if (section == 0) - return @"Actions"; + return SKLocalizedString(@"Actions"); else if (section == 1) - return @"Services"; + return SKLocalizedString(@"Services"); } return nil; @@ -314,7 +314,7 @@ - (void)save [self.tableView setEditing:NO animated:YES]; [self rebuildTableDataAnimated:YES]; - [self.navigationItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Edit" + [self.navigationItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:SKLocalizedString(@"Edit") style:UIBarButtonItemStyleBordered target:self action:@selector(edit)] autorelease] animated:YES]; diff --git a/ShareKit.bundle/de.lproj/Localizable.strings b/ShareKit.bundle/de.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..e47a8fc5b6094c4e0815ed3c54d9d8c598ae3041 GIT binary patch literal 8606 zcmd6sU2j@P5Qg`#&slLjN!I z-jbfN{&%Ep7CuUEU!UfgfA^b(C6H`K%3R`|P(n`=`=-6A=TsH0NhUJ&9`zo@A-p z=tdmNEVeO=*}U#*&alMCG~!6Hw(uxf?L>U=e-QpI;q;4SS-qU$HZ}@>)=DO=NzP-a zTlsv~F)<@JutQhBM{;Nb7TPn+xtklZb2WF$vCl(j)Yk`FT3h> z)DiDfDY9lc*GEsH%i6A|kgmCWCkLqsW4*JwiPzi88){|m3RMm2_afTp%O)(w!dTU$ z5Ff$qS%86HZF{|5WEs^B&y4x>68r+|9N{lz&!VfxVxS&Kf6VLSW=YfdUT7>8(ZinynrV;p!>_V;mm7d)gU5AbeLwfqm zZk(D%UX=H``Ks+U+bnl)YY}^?#XI@h6EXa@^d*4I5M1{~m=#vkz?Hdt!);)<#?uq&2VyYL_%C`;tKl#`F{XYUR#DnUCth+_u$xZf z&W~aX`=Y-7IA762_Vu<&v-|ue_FnkM%5(GHQ}4FlFOvOcDO;tM*h4?JyWk6*X#5u2 z&-?2o+?)3?_WW#V=WRQGE{oHR^=sV)_ZTcZ}xnHfAD_G?=26Xa!x%#Ju3Ma_k zZSSCxk#p$bM#l8G_w(>UYrwgYth750c1Y|we03~esle!2Mn7_%d>Lzw%614Fuc+}> z3sbxa0lOc%Qk=W2;Vu?zb?P&=T8%%&^`KX#b;D+U=d`~jNA)!3K>7ZzzJlV9Rk;&= zDxZO2sC6nl%{g)`{Y{9j)>ZubT@2=CFLfP{6SnXRh;<~g-*z3`hg3OIkNhz#T7>lV z$NVM0F2Tz1`nNwkh)M l8Oc4N-FP35^-VSsI=NI^Ia&RksU=U7uen4M5)Z}l{{RmSfoK2# literal 0 HcmV?d00001 diff --git a/ShareKit.bundle/en.lproj/Localizable.strings b/ShareKit.bundle/en.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..099468ec1b32e93f05084de156866e2943156693 GIT binary patch literal 8582 zcmd6sNpBlR5QY1kUokO|TOiv&P6`4cFo3N1mN}m^cKa!r2 zK2N1>8t$a`Oy6die-E35C6Mez%<$4PkdK*1?_>$P6X83q#nXIZGfpHq)9aJ`pN8{H zd-I9Scp*t*ywRL0{1AT4=CnPtS;vx}2q!qTsCm|WVlxs8+gQSwNxhDK55qxxIX2~Z z@?s$SWF*J&SQz+dvObcZmsxD5nqwm-aS|)!PIKqAc*^l4y$Bzq0Y12wC(`Jn?&EDl z3dCF%FY|Ge?n~obdUKTWu_Q&kInMAIkw00`S+qc}6u|McEXGBfE_b$E;qLeXVKq5irbI zTGnqVm-M~XJXTZN-Bi*wQ%uw#Jz=DGvgx0a@uVv4oYsX@!eGIE!-XB*>n#T7+W1%R=dIzT} z#%Z~=UG2D$FT;?X5E!Lyo{-Mb*^l9yOu3>SZ zc!zrN>+HTZ@qypGU+H}=>BI0;ueoN9$m(V!eeS1AS-L zP4}TL>U-KeYn#nB%l-RaG?Pu=+Z(H_m!+Jsc7hvhLe^Hj1N}OYpTp=MNYC|zTBTnQ z1M(w%v&`pyKZfl*YPeCUJAy3!(y6U?;x(s4XKAXIR6YF~SG@aKOuN*a*nKQqK^Yv) z+g0p-8|7^m=^21ybdDy&_h(^Q3~*ze%Djy{`k-3i41X@)$&jO7dcLjRE|#F%`44BB zJI|BCU-z_~ADii1hH9n#D_mLL_vjdKfYTR$#Ip-Nbn7)#Ph&@;NBk%x+h$bCu=T;T zgEEc`zKc(gu3^r>C-=Z9jkYujDb#>&S^!;J!~ zVtc){u_%wKz3R5py?OQhu6Vd*BcfDwPa~5DVm`I#{i5t_t8055?S?q0!6DXiJE^gE zvYkM>ZKFTiDZku-xR2ZF>B@iE898rU>UAxzSfTl}`+z*|N+(3t$`Z|X9_+?OR}@XA z4TSVO?!EAz8#Gq-6qR?l`s%m|r#H9su!!pGphsXm9Hu*C+VjvvX&s$-$z8!_I*mKO zi7j@I$!!`nu)Viknv>6O;@S)U$UHaf1FhZme+oydTgtL@B=)eLb0%h|ekg7Ad+g;B z$(#2v_WW#V=WRQGE)4AWOFztxz)^?#Q`E?X)1*?8f>gcpTHB>l34(`_uIvF*G z9&Thn+2fgokIDh(Myk^8IM^Yv=SbPHdZh!SXA$S;Jo!4-5-RHp zp)19?Ne(x$VA*M}*s>dciuquz^t@p+zjNANQ$qDP) literal 0 HcmV?d00001 diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index c878351a..3a1b0a7a 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -85,6 +85,7 @@ 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */; }; 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; 43EF406E11D3FFF800B1F700 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43EF406D11D3FFF800B1F700 /* Security.framework */; }; + 7882FB2511F5005F006E7742 /* ShareKit.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 7882FB2411F5005F006E7742 /* ShareKit.bundle */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -236,6 +237,7 @@ 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTumblr.m; sourceTree = ""; }; 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 43EF406D11D3FFF800B1F700 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 7882FB2411F5005F006E7742 /* ShareKit.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = ShareKit.bundle; sourceTree = SOURCE_ROOT; }; 8D1107310486CEB800E47090 /* ShareKit-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ShareKit-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -344,6 +346,7 @@ 43A5383311DBE493004A1712 /* RootViewController.m */, 43A5383411DBE493004A1712 /* ShareKitAppDelegate.h */, 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */, + 7882FB2411F5005F006E7742 /* ShareKit.bundle */, ); name = "Example Project"; sourceTree = ""; @@ -756,6 +759,7 @@ 43A5382811DBE480004A1712 /* example.pdf in Resources */, 43A5382911DBE480004A1712 /* sanFran.jpg in Resources */, 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */, + 7882FB2511F5005F006E7742 /* ShareKit.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 2f9da8679a2240338c2354c4ec1be98326d57b24 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 20 Jul 2010 00:20:39 +0200 Subject: [PATCH 16/50] completed german localization --- ShareKit.bundle/de.lproj/Localizable.strings | Bin 8606 -> 9084 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ShareKit.bundle/de.lproj/Localizable.strings b/ShareKit.bundle/de.lproj/Localizable.strings index e47a8fc5b6094c4e0815ed3c54d9d8c598ae3041..5099818d22616e8891b9ee97e8c2da5dd2094a4e 100644 GIT binary patch literal 9084 zcmc(k&2C#q425Uir?@rHUE#DqS1AfqN#ww2evHa#k?dqg{y{9+mE<_dgLd0ZpP{Ru z?fHhLIrrX?EhlLT!Im_a!#N}mIh@fye{ZBwI!fa-PseGN4pXDgO?s5Sy-FMU{Db~B z(r%h)>_q>|r{AY9^sKL8CaLW-m99h0sB5{G^}W>7x)xS^la?!H$J6?3tk}9lTwniz z&@Ho7j^I%`72eZyuJK0i2l_vd%_n*vNphZEOXI#iEeccv$uA@^&XN;(u`kV2q)ze* z_+)lzH~t%DPvPA_T8^28&omzlGwGV@Q^@w8*o+-XF7&$4s`G@WJ(}$&_}FG_NfLWc zHK$2mr5}qq_6+R)#OB`}0 z$rc}X1Y@mDTuKiP(w<&(jqYnscpSc-2{@QiyIhG*q{Cz_a^3aMq>K87{{1XVM>NwK zZ#4qP8!;KK^4vN|s)$+0Ec^r}JaMS;BQYzGb=T`7Wgap4OYg9bZ*-Jzq?vcRGDq-2 z&%IvRs%D+}5hNa+RX&_ZCwp>Pf%}-u<3t|2ESBcK=kg8}eyacYt;vYZ8`e|Pv$bOf zQnJOFZME4wUwUgK>+twAz0W$#8_vZh)sWg#>KV~ut#i#MkI+RA0It3K$#<_Y@CYAlubyXL3!e6u2q5y7IXjk4QahkOH z>eYH7Hkg-?j~G*%=vMx`L}=DgVL117J!N~{MYa|jqcUSDyJlp9XRddEyDdIO?YpP7 ztV7r-ScdlVeC90YnSYJ##!tG3=!Sfj<7St*uZR#IB4C(r$|G`PoGSyT6^|VZB?tPs zG}H=~9h??FK8xJ)b#Zvb=vqpo*Qpfr)ibf{RMOPn&HOzg)U^+eFvBeE)&NJ}u12fY zuqt4A*ku>^BiGsPmU zjB@Rzl6@^-)n?evS$3Glw2ACtFN!*_pYzYULQb62`i1PhxpJ1(vW{V_or$xz-5=mb z%kpj2b=X9t z20M5?S8FjW?YTZ)bf_wsS=UR|G1sup)_(X#!AoFJDF+h7ceC1&rsj~i(O$I z4AEP`JGvD+AJa`*uQO8~(yOvV*gZ|R&k9T0U6!3XyISZ(sRrF%%TK0t-jJVo&2BjC z%*L(5v9!Tn-t8PvTHWYmZaZ|_;9sMcFtZ&5!J;N3F!nb^WE zL`UHkMxAW$)b+d=baWj^&pZ9$2dj2o`RMD~J2NA6r|Wl5{LW!_Uht&s`mWFRu*q&8 z$dzDIM5(qfJAPOex284ZH|O_yL95JJz~3c%|y=_%J)3<{p7ufi-mR zW7T#0l`1f8_ntMnE#ThWIyL9*KrEp5ux{w3PK*8vhTm}wG=r1Ikxm76TM;teYd+6j zDNp!&n&G!1;N+Y6((=%-+erJj6hDo$&+~S_;+m*8roqnbiyRwnX<7I9(gyELIk%VD zUsip~A#R9jckuP6R!@hric=WX-%c844R>oqBP?F1FF97!@W7Ei*(rXrtl@W(xV3dpmAALu)w+8KtCgLx^}L>0 zwX9m@>Hb~_?%!lBw-~VpIwCm4erEe4cF@1l8_-droKO6!T-n4w$C_Qt+KA|TdPrYf&AwB zX{_z?Vs%!wQL{Hh#k^f?$x+uvN7e1vy1xf?W&7F04Bva}5nn$~xNWt2^K~-AZ=8dL uaEtm%KE2R8ca%iTcLj2+)}z$=V7JOVRw5fJv#g_!3Tms7-*hB>hWrZ^f#O~O delta 800 zcmZvZ&r1|x7{}kuot^#JuCu$-Ij4 zPi^U9e*E;y*z`&G?HB14;Px*;@|)Q8caWx`FHpxopoaF~ITV69ECna=ELg)#s1H`C zgdd>={0dnR!=upS2^7O+d+setE{f0K-mMK>FxTQ;0q zw8=LSNwwputYBMy12s7bT`r)Ms*pbHIN49>M^5(1{fN>)T``-Rj5uzVwFDlf4d|)? wLrosrcc6Ad$OuktF_S-HE@t#qtq%z;)?6rpWv$Z07SWkCP|ixnAy0I%zlxgew*UYD From a8785b8ce00f9184a9f452d702938e07fa5d2718 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 20 Jul 2010 00:24:25 +0200 Subject: [PATCH 17/50] add localization for twitter --- .../Sharers/Services/Twitter/SHKTwitter.m | 2 +- ShareKit.bundle/de.lproj/Localizable.strings | Bin 9084 -> 9286 bytes ShareKit.bundle/en.lproj/Localizable.strings | Bin 8582 -> 8744 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index 5c564e62..fa466848 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -115,7 +115,7 @@ - (void)promptAuthorization + (NSString *)authorizationFormCaption { - return @"Create a free account at Twitter.com"; + return SKLocalizedString(@"Create a free account at Twitter.com"); } + (NSArray *)authorizationFormFields diff --git a/ShareKit.bundle/de.lproj/Localizable.strings b/ShareKit.bundle/de.lproj/Localizable.strings index 5099818d22616e8891b9ee97e8c2da5dd2094a4e..e7b810150011f2640292b0a0f78dcfd1c4048c71 100644 GIT binary patch delta 72 zcmez4cFbc#11Ga1L*C?ePSwd*_)WM&7|Izk8A^aKb@FwdVre8kLlJ`>Lo!1?LoS07 SgEa%!mL&oH0PSwq2To)t(aZdImhH{2Xh7yL7$%=xWvTz Date: Mon, 26 Jul 2010 11:52:50 +0200 Subject: [PATCH 18/50] BUGFIX: filter out sharers that can't share, thus create no button but were evaluated on clickedButtonAtIndex. This produced a black screen when no mail client was setup, mail was a favorite and the user pressed "more". --- Classes/ShareKit/UI/SHKActionSheet.m | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Classes/ShareKit/UI/SHKActionSheet.m b/Classes/ShareKit/UI/SHKActionSheet.m index 6fd6c1bb..516a1527 100644 --- a/Classes/ShareKit/UI/SHKActionSheet.m +++ b/Classes/ShareKit/UI/SHKActionSheet.m @@ -56,13 +56,19 @@ + (SHKActionSheet *)actionSheetForType:(SHKShareType)type as.sharers = [SHK favoriteSharersForType:type]; // Add buttons for each favoriate sharer + NSMutableArray *activeSharer = [NSMutableArray array]; id class; for(NSString *sharerId in as.sharers) { class = NSClassFromString(sharerId); - if ([class canShare]) + if ([class canShare]) { [as addButtonWithTitle: [class sharerTitle] ]; + [activeSharer addObject:as]; + } } + + // filter out sharers that cannot share + as.sharers = activeSharer; // Add More button [as addButtonWithTitle:SKLocalizedString(@"More...")]; From 8081db83ff74dc3d857b2e95eaada4870724e532 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 26 Jul 2010 12:01:04 +0200 Subject: [PATCH 19/50] fix: add single sharer, not class --- Classes/ShareKit/UI/SHKActionSheet.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/UI/SHKActionSheet.m b/Classes/ShareKit/UI/SHKActionSheet.m index 516a1527..c0ee423b 100644 --- a/Classes/ShareKit/UI/SHKActionSheet.m +++ b/Classes/ShareKit/UI/SHKActionSheet.m @@ -63,7 +63,7 @@ + (SHKActionSheet *)actionSheetForType:(SHKShareType)type class = NSClassFromString(sharerId); if ([class canShare]) { [as addButtonWithTitle: [class sharerTitle] ]; - [activeSharer addObject:as]; + [activeSharer addObject:sharerId]; } } From 3a6a7466688321db77bb76c19a7de714af3a1cb1 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Tue, 27 Jul 2010 10:24:40 -0700 Subject: [PATCH 20/50] New: - SHKPhotoAlbum: Save images to photo album action - Facebook accepts text sharing Fixes: - SHKItem now carries over full item when sharing - Crash when saving items offline that did not contain custom variables - Modal popups would not go away when using pagesheet modal type on iPad - Editing sharers now affects actionsheet choices - Race condition in SHKShareMenu Improvements: - Improved display of SHKTwitterForm on iPad - Facebook uses text variable when sharing urls to repopulate status message - SHKMail now uses up to date template, improved handling of text when it's available in SHKItem - Updated SHKActionSheet to not override delegate, now you can assign your own delegate Code Refactoring: - Renamed SHLocalizedString to use proper SHK prefix - Updated SHKLocalizedString to work like stringWithFormat - Removed/Combined some localization strings --- Classes/Example/RootViewController.m | 13 +- .../Core/Base Sharer Classes/SHKOAuthSharer.m | 26 ++-- .../Core/Base Sharer Classes/SHKSharer.m | 64 ++++------ Classes/ShareKit/Core/SHK.h | 5 +- Classes/ShareKit/Core/SHK.m | 89 +++++++++++-- Classes/ShareKit/Core/SHKItem.m | 4 +- Classes/ShareKit/Core/SHKSharers.plist | 1 + .../Customize UI/SHKCustomFormController.m | 98 --------------- .../de.lproj/Localizable.strings | Bin 0 -> 7834 bytes .../en.lproj/Localizable.strings | Bin 0 -> 7430 bytes .../ShareKit/Sharers/Actions/Copy/SHKCopy.m | 4 +- .../ShareKit/Sharers/Actions/Email/SHKMail.h | 11 +- .../ShareKit/Sharers/Actions/Email/SHKMail.m | 118 ++++++++---------- .../Actions/Open in Safari/SHKSafari.m | 2 +- .../Actions/Save to Album/SHKPhotoAlbum.h | 36 ++++++ .../Actions/Save to Album/SHKPhotoAlbum.m | 80 ++++++++++++ .../Sharers/Services/Delicious/SHKDelicious.m | 12 +- .../Services/Facebook/SHKFBStreamDialog.h | 19 +++ .../Services/Facebook/SHKFBStreamDialog.m | 40 ++++++ .../Sharers/Services/Facebook/SHKFacebook.m | 27 +++- .../Services/Google Reader/SHKGoogleReader.m | 24 ++-- .../Services/Instapaper/SHKInstapaper.m | 18 +-- .../Sharers/Services/Pinboard/SHKPinboard.m | 16 +-- .../Services/Read It Later/SHKReadItLater.m | 12 +- .../Sharers/Services/Tumblr/SHKTumblr.m | 40 +++--- .../Sharers/Services/Twitter/SHKTwitter.m | 16 +-- .../Sharers/Services/Twitter/SHKTwitterForm.h | 2 + .../Sharers/Services/Twitter/SHKTwitterForm.m | 77 +++++++----- Classes/ShareKit/UI/SHKActionSheet.h | 1 - Classes/ShareKit/UI/SHKActionSheet.m | 27 ++-- Classes/ShareKit/UI/SHKFormFieldCell.h | 2 +- Classes/ShareKit/UI/SHKFormFieldCell.m | 38 +++--- Classes/ShareKit/UI/SHKShareMenu.m | 12 +- ShareKit.xcodeproj/project.pbxproj | 37 ++++-- 34 files changed, 571 insertions(+), 400 deletions(-) create mode 100644 Classes/ShareKit/ShareKit.bundle/de.lproj/Localizable.strings create mode 100644 Classes/ShareKit/ShareKit.bundle/en.lproj/Localizable.strings create mode 100644 Classes/ShareKit/Sharers/Actions/Save to Album/SHKPhotoAlbum.h create mode 100644 Classes/ShareKit/Sharers/Actions/Save to Album/SHKPhotoAlbum.m create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h create mode 100644 Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m diff --git a/Classes/Example/RootViewController.m b/Classes/Example/RootViewController.m index 034de581..60b2e4a9 100644 --- a/Classes/Example/RootViewController.m +++ b/Classes/Example/RootViewController.m @@ -45,23 +45,23 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N switch (indexPath.row) { case 0: - cell.textLabel.text = SKLocalizedString(@"Sharing a Link"); + cell.textLabel.text = @"Sharing a Link"; break; case 1: - cell.textLabel.text = SKLocalizedString(@"Sharing an Image"); + cell.textLabel.text = @"Sharing an Image"; break; case 2: - cell.textLabel.text = SKLocalizedString(@"Sharing Text"); + cell.textLabel.text = @"Sharing Text"; break; case 3: - cell.textLabel.text = SKLocalizedString(@"Sharing a File"); + cell.textLabel.text = @"Sharing a File"; break; //case 4: - // cell.textLabel.text = SKLocalizedString(@"Logout of All Services"); + // cell.textLabel.text = @"Logout of All Services"; // break; } @@ -81,6 +81,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath break; case 1: + [self.navigationController pushViewController:[[[ExampleShareImage alloc] initWithNibName:nil bundle:nil] autorelease] animated:YES]; break; @@ -105,7 +106,5 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface } - - @end diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m index d27c4ea3..5b39f324 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m @@ -76,7 +76,7 @@ - (void)promptAuthorization - (void)tokenRequest { - [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Connecting...")]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Connecting...")]; OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:requestURL consumer:consumer @@ -121,17 +121,17 @@ - (void)tokenRequestTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData * else // TODO - better error handling here - [self tokenRequestTicket:ticket didFailWithError:[SHK error:SKLocalizedString(@"There was a problem requesting authorization from %@"), [self sharerTitle]]]; + [self tokenRequestTicket:ticket didFailWithError:[SHK error:SHKLocalizedString(@"There was a problem requesting authorization from %@"), [self sharerTitle]]]; } - (void)tokenRequestTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error { [[SHKActivityIndicator currentIndicator] hide]; - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Request Error") - message:error!=nil?[error localizedDescription]:SKLocalizedString(@"There was an error while sharing") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Request Error") + message:error!=nil?[error localizedDescription]:SHKLocalizedString(@"There was an error while sharing") delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } @@ -153,10 +153,10 @@ - (void)tokenAuthorizeView:(SHKOAuthView *)authView didFinishWithSuccess:(BOOL)s if (!success) { - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Authorize Error") - message:error!=nil?[error localizedDescription]:SKLocalizedString(@"There was an error while authorizing") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Authorize Error") + message:error!=nil?[error localizedDescription]:SHKLocalizedString(@"There was an error while authorizing") delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } @@ -184,7 +184,7 @@ - (void)tokenAccess - (void)tokenAccess:(BOOL)refresh { if (!refresh) - [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Authenticating...")]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Authenticating...")]; OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:accessURL consumer:consumer @@ -231,17 +231,17 @@ - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *) else // TODO - better error handling here - [self tokenAccessTicket:ticket didFailWithError:[SHK error:SKLocalizedString(@"There was a problem requesting access from %@"), [self sharerTitle]]]; + [self tokenAccessTicket:ticket didFailWithError:[SHK error:SHKLocalizedString(@"There was a problem requesting access from %@", [self sharerTitle])]]; } - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error { [[SHKActivityIndicator currentIndicator] hide]; - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Access Error") - message:error!=nil?[error localizedDescription]:SKLocalizedString(@"There was an error while sharing") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Access Error") + message:error!=nil?[error localizedDescription]:SHKLocalizedString(@"There was an error while sharing") delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m index de05319a..2decedd6 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m @@ -181,26 +181,14 @@ + (id)shareItem:(SHKItem *)i { [SHK pushOnFavorites:[self sharerId] forType:i.shareType]; - switch (i.shareType) - { - case SHKShareTypeURL: - return [self shareURL:i.URL title:i.title]; - break; - - case SHKShareTypeImage: - return [self shareImage:i.image title:i.title]; - break; - - case SHKShareTypeText: - return [self shareText:i.text]; - break; - - case SHKShareTypeFile: - return [self shareFile:i.data filename:i.filename mimeType:i.mimeType title:i.title]; - break; - } + // Create controller and set share options + SHKSharer *controller = [[self alloc] init]; + controller.item = i; - return nil; + // share and/or show UI + [controller share]; + + return [controller autorelease]; } + (id)shareURL:(NSURL *)url @@ -322,10 +310,10 @@ - (void)promptAuthorization { if (!quiet) { - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Offline") - message:[NSString stringWithFormat:SKLocalizedString(@"You must be online to login to %@"), [self sharerTitle]] + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Offline") + message:SHKLocalizedString(@"You must be online to login to %@", [self sharerTitle]) delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } return; @@ -349,7 +337,7 @@ - (void)setShouldAutoShare:(BOOL)b - (void)authorizationFormShow { // Create the form - SHKCustomFormController *form = [[SHKCustomFormController alloc] initWithStyle:UITableViewStyleGrouped title:SKLocalizedString(@"Login") rightButtonTitle:SKLocalizedString(@"Login")]; + SHKCustomFormController *form = [[SHKCustomFormController alloc] initWithStyle:UITableViewStyleGrouped title:SHKLocalizedString(@"Login") rightButtonTitle:SHKLocalizedString(@"Login")]; [form addSection:[self authorizationFormFields] header:nil footer:[self authorizationFormCaption]]; form.delegate = self; form.validateSelector = @selector(authorizationFormValidate:); @@ -407,8 +395,8 @@ - (NSArray *)authorizationFormFields + (NSArray *)authorizationFormFields { return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Username") key:@"username" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:SKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], + [SHKFormFieldSettings label:SHKLocalizedString(@"Username") key:@"username" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:SHKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], nil]; } @@ -450,7 +438,7 @@ - (void)show { SHKCustomFormController *rootView = [[SHKCustomFormController alloc] initWithStyle:UITableViewStyleGrouped title:nil - rightButtonTitle:[NSString stringWithFormat:SKLocalizedString(@"Send to %@"), [[self class] sharerTitle]] + rightButtonTitle:SHKLocalizedString(@"Send to %@", [[self class] sharerTitle]) ]; [rootView addSection:[self shareFormFieldsForType:item.shareType] header:nil footer:item.URL!=nil?item.URL.absoluteString:nil]; @@ -458,10 +446,10 @@ - (void)show { [rootView addSection: [NSArray arrayWithObject: - [SHKFormFieldSettings label:SKLocalizedString(@"Auto Share") key:@"autoShare" type:SHKFormFieldTypeSwitch start:([self shouldAutoShare]?SHKFormFieldSwitchOn:SHKFormFieldSwitchOff)] + [SHKFormFieldSettings label:SHKLocalizedString(@"Auto Share") key:@"autoShare" type:SHKFormFieldTypeSwitch start:([self shouldAutoShare]?SHKFormFieldSwitchOn:SHKFormFieldSwitchOff)] ] header:nil - footer:SKLocalizedString(@"Enable auto share to skip this step in the future.")]; + footer:SHKLocalizedString(@"Enable auto share to skip this step in the future.")]; } rootView.delegate = self; @@ -484,7 +472,7 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:SHKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], nil]; return nil; @@ -577,10 +565,10 @@ - (BOOL)tryToSend else if (!quiet) { - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Offline") - message:[NSString stringWithFormat:SKLocalizedString(@"You must be online in order to share with %@"), [self sharerTitle]] + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Offline") + message:SHKLocalizedString(@"You must be online in order to share with %@", [self sharerTitle]) delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; return YES; @@ -609,13 +597,13 @@ - (BOOL)send - (void)sharerStartedSending:(SHKSharer *)sharer { if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:[NSString stringWithFormat:SKLocalizedString(@"Saving to %@"), [[self class] sharerTitle]]]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Saving to %@", [[self class] sharerTitle])]; } - (void)sharerFinishedSending:(SHKSharer *)sharer { if (!quiet) - [[SHKActivityIndicator currentIndicator] displayCompleted:SKLocalizedString(@"Saved!")]; + [[SHKActivityIndicator currentIndicator] displayCompleted:SHKLocalizedString(@"Saved!")]; } - (void)sharer:(SHKSharer *)sharer failedWithError:(NSError *)error shouldRelogin:(BOOL)shouldRelogin @@ -624,10 +612,10 @@ - (void)sharer:(SHKSharer *)sharer failedWithError:(NSError *)error shouldRelogi { [[SHKActivityIndicator currentIndicator] hide]; - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Error") - message:sharer.lastError!=nil?[sharer.lastError localizedDescription]:SKLocalizedString(@"There was an error while sharing") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Error") + message:sharer.lastError!=nil?[sharer.lastError localizedDescription]:SHKLocalizedString(@"There was an error while sharing") delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; if (shouldRelogin) @@ -688,7 +676,7 @@ - (void)sendDidFinish - (void)sendDidFailShouldRelogin { - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"Could not authenticate you. Please relogin.")] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"Could not authenticate you. Please relogin.")] shouldRelogin:YES]; } - (void)sendDidFailWithError:(NSError *)error diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index 90cbf41a..5a5daf92 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -25,7 +25,7 @@ // // -#define SHK_VERSION @"0.1.6" +#define SHK_VERSION @"0.2.0b1" #import #import "SHKConfig.h" @@ -123,4 +123,5 @@ NSString * SHKEncode(NSString * value); NSString * SHKEncodeURL(NSURL * value); -NSString * SKLocalizedString(NSString* key); +NSString* SHKLocalizedString(NSString* key, ...); +void SHKSwizzle(Class c, SEL orig, SEL new); diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m index e6fcc3b0..b9606f85 100644 --- a/Classes/ShareKit/Core/SHK.m +++ b/Classes/ShareKit/Core/SHK.m @@ -32,6 +32,8 @@ #import "SHKOfflineSharer.h" #import "SFHFKeychainUtils.h" #import "Reachability.h" +#import +#import @implementation SHK @@ -41,7 +43,7 @@ @implementation SHK @synthesize offlineQueue; static SHK *currentHelper = nil; - +BOOL SHKinit; + (SHK *)currentHelper @@ -52,6 +54,16 @@ + (SHK *)currentHelper return currentHelper; } ++ (void)initialize +{ + [super initialize]; + + if (!SHKinit) + { + SHKSwizzle([MFMailComposeViewController class], @selector(viewDidDisappear:), @selector(SHKviewDidDisappear:)); + SHKinit = YES; + } +} - (void)dealloc { @@ -143,6 +155,11 @@ - (void)showViewController:(UIViewController *)vc self.pendingView = nil; } +- (void)hideCurrentViewController +{ + [self hideCurrentViewControllerAnimated:YES]; +} + - (void)hideCurrentViewControllerAnimated:(BOOL)animated { if (isDismissingView) @@ -162,6 +179,13 @@ - (void)hideCurrentViewControllerAnimated:(BOOL)animated } } +- (void)showPendingView +{ + if (pendingView) + [self showViewController:pendingView]; +} + + - (void)viewWasDismissed { self.isDismissingView = NO; @@ -171,7 +195,10 @@ - (void)viewWasDismissed if (pendingView) { - [self showViewController:pendingView]; + // This is an ugly way to do it, but it works. + // There seems to be an issue chaining modal views otherwise + // See: http://github.com/ideashower/ShareKit/issues#issue/24 + [self performSelector:@selector(showPendingView) withObject:nil afterDelay:0.02]; return; } } @@ -249,7 +276,7 @@ + (NSArray *)favoriteSharersForType:(SHKShareType)type break; case SHKShareTypeText: - favoriteSharers = [NSArray arrayWithObjects:@"SHKMail",@"SHKTwitter", nil]; + favoriteSharers = [NSArray arrayWithObjects:@"SHKMail",@"SHKTwitter",@"SHKFacebook", nil]; break; case SHKShareTypeFile: @@ -261,6 +288,23 @@ + (NSArray *)favoriteSharersForType:(SHKShareType)type [self setFavorites:favoriteSharers forType:type]; } + // Make sure the favorites are not using any exclusions, remove them if they are. + NSArray *exclusions = [[NSUserDefaults standardUserDefaults] objectForKey:@"SHKExcluded"]; + if (exclusions != nil) + { + NSMutableArray *newFavs = [favoriteSharers mutableCopy]; + for(NSString *sharerId in exclusions) + { + [newFavs removeObject:sharerId]; + } + + // Update + favoriteSharers = [NSArray arrayWithArray:newFavs]; + [self setFavorites:favoriteSharers forType:type]; + + [newFavs release]; + } + return favoriteSharers; } @@ -516,14 +560,33 @@ + (BOOL)connected return result; } +void SHKSwizzle(Class c, SEL orig, SEL new) +{ + Method origMethod = class_getInstanceMethod(c, orig); + Method newMethod = class_getInstanceMethod(c, new); + if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) + class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); + else + method_exchangeImplementations(origMethod, newMethod); +} -NSString* SKLocalizedString(NSString* key) { - static NSBundle* bundle = nil; - if (!bundle) { - NSString* path = [[[NSBundle mainBundle] resourcePath] - stringByAppendingPathComponent:@"ShareKit.bundle"]; - bundle = [[NSBundle bundleWithPath:path] retain]; - } - - return [bundle localizedStringForKey:key value:key table:nil]; -} \ No newline at end of file +NSString* SHKLocalizedString(NSString* key, ...) +{ + static NSBundle* bundle = nil; + if (!bundle) + { + NSString* path = [[[NSBundle mainBundle] resourcePath] + stringByAppendingPathComponent:@"ShareKit.bundle"]; + bundle = [[NSBundle bundleWithPath:path] retain]; + } + + // Localize the format + NSString *localizedStringFormat = [bundle localizedStringForKey:key value:key table:nil]; + + va_list args; + va_start(args, key); + NSString *string = [[[NSString alloc] initWithFormat:localizedStringFormat arguments:args] autorelease]; + va_end(args); + + return string; +} diff --git a/Classes/ShareKit/Core/SHKItem.m b/Classes/ShareKit/Core/SHKItem.m index 6216d833..76a44613 100644 --- a/Classes/ShareKit/Core/SHKItem.m +++ b/Classes/ShareKit/Core/SHKItem.m @@ -161,7 +161,9 @@ - (NSDictionary *)dictionaryRepresentation NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:0]; [dictionary setObject:[NSNumber numberWithInt:shareType] forKey:@"shareType"]; - [dictionary setObject:custom forKey:@"custom"]; + + if (custom != nil) + [dictionary setObject:custom forKey:@"custom"]; if (URL != nil) [dictionary setObject:[URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:@"URL"]; diff --git a/Classes/ShareKit/Core/SHKSharers.plist b/Classes/ShareKit/Core/SHKSharers.plist index b5ba9244..f4b31984 100644 --- a/Classes/ShareKit/Core/SHKSharers.plist +++ b/Classes/ShareKit/Core/SHKSharers.plist @@ -4,6 +4,7 @@ actions + SHKPhotoAlbum SHKCopy SHKMail SHKSafari diff --git a/Classes/ShareKit/Customize UI/SHKCustomFormController.m b/Classes/ShareKit/Customize UI/SHKCustomFormController.m index 9ed82a18..a83f0597 100644 --- a/Classes/ShareKit/Customize UI/SHKCustomFormController.m +++ b/Classes/ShareKit/Customize UI/SHKCustomFormController.m @@ -31,103 +31,5 @@ @implementation SHKCustomFormController // See http://getsharekit.com/customize/ for additional information on customizing -/* -- (void)viewDidLoad -{ - [super viewDidLoad]; - - // Change the background color to something yellow/paperishy - self.tableView.backgroundColor = [UIColor colorWithRed:233.0/255.0 - green:231.0/255.0 - blue:214.0/255.0 - alpha:1]; - - // Change the cell border color to match - self.tableView.separatorColor = [UIColor colorWithRed:207.0/255.0 - green:204.0/255.0 - blue:199.0/255.0 - alpha:1]; - -} - -// Customize the look of the cell -- (UITableViewCell *)tableView:(UITableView *)tableView - cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - SHKCustomFormFieldCell *cell = - (SHKCustomFormFieldCell *)[super tableView:tableView - cellForRowAtIndexPath:indexPath]; - - // lighter color - cell.textLabel.textColor = [UIColor lightGrayColor]; - - // smaller font - cell.textLabel.font = [UIFont boldSystemFontOfSize:13]; - - // more subtle cell background - cell.backgroundColor = [UIColor colorWithRed:234.0/255.0 - green:234.0/255.0 - blue:234.0/255.0 - alpha:1]; - - return cell; -} - -// Create a custom footer label so we can style it -- (UIView *)tableView:(UITableView *)tableView - viewForFooterInSection:(NSInteger)section -{ - NSString *footerTitle = [self tableView:tableView titleForFooterInSection:section]; - if (footerTitle != nil) - { - // Create a view to put the label in so we have some padding - UIView *wrapper = [[[UIView alloc] - initWithFrame:CGRectMake(0, - 0, - tableView.frame.size.width, - 50)] autorelease]; - wrapper.autoresizesSubviews = YES; - wrapper.autoresizingMask = UIViewAutoresizingFlexibleWidth; - - // Create the label - CGRect labelFrame = CGRectMake( - round(tableView.frame.size.width/2-300/2), - 0, - 300, - 50); - UILabel *label = [[[UILabel alloc] initWithFrame:labelFrame] autorelease]; - label.backgroundColor = [UIColor clearColor]; - label.opaque = NO; - label.textColor = [UIColor grayColor]; - label.font = [UIFont systemFontOfSize:13]; - - label.textAlignment = UITextAlignmentCenter; - label.lineBreakMode = UILineBreakModeWordWrap; - label.numberOfLines = 0; - - label.text = footerTitle; - - label.autoresizesSubviews = YES; - label.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | - UIViewAutoresizingFlexibleRightMargin; - - [wrapper addSubview:label]; - - return wrapper; - } - - return nil; -} - -// Set the height of our label (when we have one to display) -- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section -{ - NSString *footerTitle = [self tableView:tableView titleForFooterInSection:section]; - if (footerTitle != nil) - return 50; - - return 0; -} -*/ @end diff --git a/Classes/ShareKit/ShareKit.bundle/de.lproj/Localizable.strings b/Classes/ShareKit/ShareKit.bundle/de.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..97829067856816cd80ba34acad1ed4b16f557608 GIT binary patch literal 7834 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 udBR;endbLEbB -@interface SHKMail : SHKSharer +@interface SHKMail : SHKSharer { } -+ (id)mail:(NSString *)body - subject:(NSString *)subject - to:(NSArray *)to - cc:(NSArray *)cc - bcc:(NSArray *)bcc - attachment:(NSData *)attachment -attachmentMimeType:(NSString *)mimeType -attachmentFileName:(NSString *)filename; +- (BOOL)sendMail; @end diff --git a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m index 53d23bb2..bab1a310 100644 --- a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m +++ b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m @@ -44,22 +44,6 @@ - (void)SHKviewDidDisappear:(BOOL)animated @implementation SHKMail -#import -void SHKSwizzle(Class c, SEL orig, SEL new) -{ - Method origMethod = class_getInstanceMethod(c, orig); - Method newMethod = class_getInstanceMethod(c, new); - if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) - class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); - else - method_exchangeImplementations(origMethod, newMethod); -} - -+ (void)initialize -{ - SHKSwizzle([MFMailComposeViewController class], @selector(viewDidDisappear:), @selector(SHKviewDidDisappear:)); -} - #pragma mark - #pragma mark Configuration : Service Defination @@ -113,68 +97,68 @@ - (BOOL)shouldAutoShare } -#pragma mark - -#pragma mark Share Types - -+ (id)shareURL:(NSURL *)url -{ - return [self shareURL:url title:nil]; -} - -+ (id)shareURL:(NSURL *)url title:(NSString *)title -{ - return [self mail:url.absoluteString subject:title to:nil cc:nil bcc:nil attachment:nil attachmentMimeType:nil attachmentFileName:nil]; -} - -+ (id)shareImage:(UIImage *)image title:(NSString *)title -{ - return [self mail:nil subject:title to:nil cc:nil bcc:nil attachment:UIImageJPEGRepresentation(image, 1) attachmentMimeType:@"image/jpeg" attachmentFileName:@"Image.jpg"]; -} - -+ (id)shareText:(NSString *)text -{ - return [self mail:text subject:nil to:nil cc:nil bcc:nil attachment:nil attachmentMimeType:nil attachmentFileName:nil]; -} - -+ (id)shareFile:(NSData *)file filename:(NSString *)filename mimeType:(NSString *)mimeType title:(NSString *)title -{ - return [self mail:[NSString stringWithFormat:SKLocalizedString(@"Attached: %@"), title] - subject:filename to:nil cc:nil bcc:nil - attachment:file attachmentMimeType:mimeType attachmentFileName:filename]; -} - - - #pragma mark - #pragma mark Share API Methods -+ (id)mail:(NSString *)body - subject:(NSString *)subject - to:(NSArray *)to - cc:(NSArray *)cc - bcc:(NSArray *)bcc - attachment:(NSData *)attachment -attachmentMimeType:(NSString *)mimeType -attachmentFileName:(NSString *)filename +- (BOOL)send { - MFMailComposeViewController *mailController = [[[MFMailComposeViewController alloc] init] autorelease]; - mailController.mailComposeDelegate = [[[self alloc] init] autorelease]; + if (![self validateItem]) + return NO; - [mailController setSubject:subject]; - [mailController setMessageBody:body isHTML:YES]; + return [self sendMail]; // Put the actual sending action in another method to make subclassing SHKMail easier +} + +- (BOOL)sendMail +{ + MFMailComposeViewController *mailController = [[[MFMailComposeViewController alloc] init] autorelease]; + mailController.mailComposeDelegate = self; - [mailController setToRecipients:to]; - [mailController setCcRecipients:cc]; - [mailController setBccRecipients:bcc]; + NSString *body = [item customValueForKey:@"body"]; - if (attachment) - [mailController addAttachmentData:attachment mimeType:mimeType fileName:filename]; + if (body == nil) + { + if (item.text != nil) + body = item.text; + + if (item.URL != nil) + { + NSString *urlStr = [item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + if (body != nil) + body = [body stringByAppendingFormat:@"

%@", urlStr]; + + else + body = urlStr; + } + + if (item.data) + { + NSString *attachedStr = SHKLocalizedString(@"Attached: %@", item.title ? item.title : item.filename); + + if (body != nil) + body = [body stringByAppendingFormat:@"

%@", attachedStr]; + + else + body = attachedStr; + + [mailController addAttachmentData:item.data mimeType:item.mimeType fileName:item.filename]; + } + + if (item.image) + [mailController addAttachmentData:UIImageJPEGRepresentation(item.image, 1) mimeType:@"image/jpeg" fileName:@"Image.jpg"]; + + + // save changes to body + [item setCustomValue:body forKey:@"body"]; + } - // How to allow devs to attach present the view how they want o + [mailController setSubject:item.title]; + [mailController setMessageBody:body isHTML:YES]; + [[SHK currentHelper] showViewController:mailController]; - return mailController; + return YES; } - (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error diff --git a/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m index 7ef4f239..709d532b 100644 --- a/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m +++ b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m @@ -37,7 +37,7 @@ @implementation SHKSafari + (NSString *)sharerTitle { - return SKLocalizedString(@"Open in Safari"); + return SHKLocalizedString(@"Open in Safari"); } + (BOOL)canShareURL diff --git a/Classes/ShareKit/Sharers/Actions/Save to Album/SHKPhotoAlbum.h b/Classes/ShareKit/Sharers/Actions/Save to Album/SHKPhotoAlbum.h new file mode 100644 index 00000000..caf00757 --- /dev/null +++ b/Classes/ShareKit/Sharers/Actions/Save to Album/SHKPhotoAlbum.h @@ -0,0 +1,36 @@ +// +// SHKPhotoAlbum.h +// ShareKit +// +// Created by Richard Johnson on 7/22/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import +#import "SHKSharer.h" + +@interface SHKPhotoAlbum : SHKSharer +{ + +} + +@end diff --git a/Classes/ShareKit/Sharers/Actions/Save to Album/SHKPhotoAlbum.m b/Classes/ShareKit/Sharers/Actions/Save to Album/SHKPhotoAlbum.m new file mode 100644 index 00000000..447ec94f --- /dev/null +++ b/Classes/ShareKit/Sharers/Actions/Save to Album/SHKPhotoAlbum.m @@ -0,0 +1,80 @@ +// +// SHKPhotoAlbum.m +// ShareKit +// +// Created by Richard Johnson on 7/22/10. + +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// + +#import "SHKPhotoAlbum.h" + + +@implementation SHKPhotoAlbum + +#pragma mark - +#pragma mark Configuration : Service Definition + ++ (NSString *)sharerTitle +{ + return @"Save to Photo Album"; +} + ++ (BOOL)canShareImage +{ + return YES; +} + ++ (BOOL)shareRequiresInternetConnection +{ + return NO; +} + ++ (BOOL)requiresAuthentication +{ + return NO; +} + + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + +- (BOOL)shouldAutoShare +{ + return YES; +} + + +#pragma mark - +#pragma mark Share API Methods + +- (BOOL)send +{ + if (item.shareType == SHKShareTypeImage) + UIImageWriteToSavedPhotosAlbum(item.image, nil, nil, nil); + + // Notify user + [[SHKActivityIndicator currentIndicator] displayCompleted:@"Saved!"]; + + return YES; +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m index 2f5106a1..5dfb2d99 100644 --- a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m +++ b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m @@ -100,7 +100,7 @@ - (BOOL)handleResponse:(SHKRequest *)aRequest { NSString *response = [aRequest getResult]; - if ([response isEqualToString:SKLocalizedString(@"401 Forbidden")]) + if ([response isEqualToString:@"401 Forbidden"]) { [self sendDidFailShouldRelogin]; return NO; @@ -117,10 +117,10 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], - [SHKFormFieldSettings label:SKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], - [SHKFormFieldSettings label:SKLocalizedString(@"Notes") key:@"text" type:SHKFormFieldTypeText start:item.text], - [SHKFormFieldSettings label:SKLocalizedString(@"Shared") key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + [SHKFormFieldSettings label:SHKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:SHKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], + [SHKFormFieldSettings label:SHKLocalizedString(@"Notes") key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:SHKLocalizedString(@"Shared") key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], nil]; return nil; @@ -209,7 +209,7 @@ - (void)sendTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data } else - error = [SHK error:SKLocalizedString(@"There was a problem saving to Delicious.")]; + error = [SHK error:SHKLocalizedString(@"There was a problem saving to Delicious.")]; [self sendTicket:ticket didFailWithError:error]; } diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h b/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h new file mode 100644 index 00000000..a5190a03 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.h @@ -0,0 +1,19 @@ +// +// SHKFBStreamDialog.h +// Adds a little bit extra control to FBStreamDialog +// +// Created by Nathan Weiner on 7/26/10. +// Copyright 2010 Idea Shower, LLC. All rights reserved. +// + +#import +#import "FBStreamDialog.h" + +@interface SHKFBStreamDialog : FBStreamDialog +{ + NSString *defaultStatus; +} + +@property (nonatomic, retain) NSString *defaultStatus; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m new file mode 100644 index 00000000..53ec2152 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFBStreamDialog.m @@ -0,0 +1,40 @@ +// +// SHKFBStreamDialog.m +// RIL +// +// Created by Nathan Weiner on 7/26/10. +// Copyright 2010 Idea Shower, LLC. All rights reserved. +// + +#import "SHKFBStreamDialog.h" +#import "SHK.h" + +@implementation SHKFBStreamDialog + +@synthesize defaultStatus; + +- (void)dealloc +{ + [defaultStatus release]; + [super dealloc]; +} + +- (void)webViewDidFinishLoad:(UIWebView *)webView +{ + [super webViewDidFinishLoad:webView]; + + if (defaultStatus) + { + // Set the pre-filled status message + [_webView stringByEvaluatingJavaScriptFromString: + [NSString stringWithFormat:@"document.getElementsByName('feedform_user_message')[0].value = decodeURIComponent('%@')", + [SHKEncode(defaultStatus) stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"] + ] + ]; + + // Make the text field bigger + [_webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByName('feedform_user_message')[0].style.height='100px'"]; + } +} + +@end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 40ce4112..1a44bbf7 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -26,7 +26,7 @@ // #import "SHKFacebook.h" - +#import "SHKFBStreamDialog.h" @implementation SHKFacebook @@ -57,6 +57,11 @@ + (BOOL)canShareURL return YES; } ++ (BOOL)canShareText +{ + return YES; +} + + (BOOL)canShareImage { return YES; @@ -124,9 +129,9 @@ - (BOOL)send { self.pendingFacebookAction = SHKFacebookPendingStatus; - FBStreamDialog* dialog = [[[FBStreamDialog alloc] init] autorelease]; + SHKFBStreamDialog* dialog = [[[SHKFBStreamDialog alloc] init] autorelease]; dialog.delegate = self; - dialog.userMessagePrompt = SKLocalizedString(@"Enter your message:"); + dialog.userMessagePrompt = SHKLocalizedString(@"Enter your message:"); dialog.attachment = [NSString stringWithFormat: @"{\ \"name\":\"%@\",\ @@ -135,6 +140,22 @@ - (BOOL)send item.title == nil ? SHKEncodeURL(item.URL) : SHKEncode(item.title), SHKEncodeURL(item.URL) ]; + dialog.defaultStatus = item.text; + dialog.actionLinks = [NSString stringWithFormat:@"[{\"text\":\"Get %@\",\"href\":\"%@\"}]", + SHKEncode(SHKMyAppName), + SHKEncode(SHKMyAppURL)]; + [dialog show]; + + } + + else if (item.shareType == SHKShareTypeText) + { + self.pendingFacebookAction = SHKFacebookPendingStatus; + + SHKFBStreamDialog* dialog = [[[SHKFBStreamDialog alloc] init] autorelease]; + dialog.delegate = self; + dialog.userMessagePrompt = @"Enter your message:"; + dialog.defaultStatus = item.text; dialog.actionLinks = [NSString stringWithFormat:@"[{\"text\":\"Get %@\",\"href\":\"%@\"}]", SHKEncode(SHKMyAppName), SHKEncode(SHKMyAppURL)]; diff --git a/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m index 467c86ab..d2aa6b6b 100644 --- a/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m +++ b/Classes/ShareKit/Sharers/Services/Google Reader/SHKGoogleReader.m @@ -72,14 +72,14 @@ + (BOOL)canShareURL + (NSString *)authorizationFormCaption { - return SKLocalizedString(@"Create a free account at Google.com/reader"); + return SHKLocalizedString(@"Create a free account at %@", @"Google.com/reader"); } + (NSArray *)authorizationFormFields { return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Email") key:@"email" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:SKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], + [SHKFormFieldSettings label:SHKLocalizedString(@"Email") key:@"email" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:SHKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], nil]; } @@ -87,7 +87,7 @@ - (void)authorizationFormValidate:(SHKFormController *)form { // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -155,15 +155,15 @@ - (void)authFinished:(SHKRequest *)aRequest NSString *message = nil; if (error != nil) - message = [error isEqualToString:@"BadAuthentication"] ? SKLocalizedString(@"Incorrect username and password") : error; + message = [error isEqualToString:@"BadAuthentication"] ? SHKLocalizedString(@"Incorrect username and password") : error; if (message == nil) // TODO - Could use some clearer message here. - message = SKLocalizedString(@"There was an error logging into Google Reader"); + message = SHKLocalizedString(@"There was an error logging into Google Reader"); - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Login Error") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Login Error") message:message delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } } @@ -176,8 +176,8 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Note") key:@"text" type:SHKFormFieldTypeText start:item.text], - [SHKFormFieldSettings label:SKLocalizedString(@"Public") key:@"share" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + [SHKFormFieldSettings label:SHKLocalizedString(@"Note") key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:SHKLocalizedString(@"Public") key:@"share" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], nil]; return nil; @@ -262,7 +262,7 @@ - (void)tokenFinished:(SHKRequest *)aRequest [self sendWithToken:[request getResult]]; else - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a problem authenticating your account.")]]; // TODO better error handling/message + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"There was a problem authenticating your account.")]]; // TODO better error handling/message } - (void)sendWithToken:(NSString *)token @@ -294,7 +294,7 @@ - (void)sendFinished:(SHKRequest *)aRequest [self sendDidFinish]; else - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a problem saving your note.")]]; // TODO better error handling/message + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"There was a problem saving your note.")]]; // TODO better error handling/message } diff --git a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m index 52c4d74f..437c94bc 100755 --- a/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m +++ b/Classes/ShareKit/Sharers/Services/Instapaper/SHKInstapaper.m @@ -57,14 +57,14 @@ + (BOOL)canShare + (NSString *)authorizationFormCaption { - return SKLocalizedString(@"Create a free account at Instapaper.com"); + return SHKLocalizedString(@"Create a free account at %@", @"Instapaper.com"); } - (void)authorizationFormValidate:(SHKFormController *)form { // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -95,14 +95,14 @@ - (void)authFinished:(SHKRequest *)aRequest else { NSString *errorMessage = nil; if (aRequest.response.statusCode == 403) - errorMessage = SKLocalizedString(@"Sorry, Instapaper did not accept your credentials. Please try again."); + errorMessage = SHKLocalizedString(@"Sorry, Instapaper did not accept your credentials. Please try again."); else - errorMessage = SKLocalizedString(@"Sorry, Instapaper encountered an error. Please try again."); + errorMessage = SHKLocalizedString(@"Sorry, Instapaper encountered an error. Please try again."); - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Login Error") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Login Error") message:errorMessage delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } } @@ -148,15 +148,15 @@ - (void)sendFinished:(SHKRequest *)aRequest { if (!aRequest.success) { if (aRequest.response.statusCode == 403) { - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"Sorry, Instapaper did not accept your credentials. Please try again.")] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"Sorry, Instapaper did not accept your credentials. Please try again.")] shouldRelogin:YES]; return; } else if (aRequest.response.statusCode == 500) { - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"The service encountered an error. Please try again later.")]]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"The service encountered an error. Please try again later.")]]; return; } - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a problem saving to Instapaper.")]]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"There was a problem saving to Instapaper.")]]; return; } diff --git a/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m index f6edf304..b0d4911a 100644 --- a/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m +++ b/Classes/ShareKit/Sharers/Services/Pinboard/SHKPinboard.m @@ -51,14 +51,14 @@ + (BOOL)canShareURL + (NSString *)authorizationFormCaption { - return SKLocalizedString(@"Create an account at http://pinboard.in"); + return SHKLocalizedString(@"Create an account at %@", @"http://pinboard.in"); } - (void)authorizationFormValidate:(SHKFormController *)form { // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -82,7 +82,7 @@ - (BOOL)handleResponse:(SHKRequest *)aRequest { NSString *response = [aRequest getResult]; - if ([response isEqualToString:SKLocalizedString(@"401 Forbidden")]) + if ([response isEqualToString:SHKLocalizedString(@"401 Forbidden")]) { [self sendDidFailShouldRelogin]; return NO; @@ -110,10 +110,10 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], - [SHKFormFieldSettings label:SKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], - [SHKFormFieldSettings label:SKLocalizedString(@"Notes") key:@"text" type:SHKFormFieldTypeText start:item.text], - [SHKFormFieldSettings label:SKLocalizedString(@"Shared") key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], + [SHKFormFieldSettings label:SHKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:SHKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], + [SHKFormFieldSettings label:SHKLocalizedString(@"Notes") key:@"text" type:SHKFormFieldTypeText start:item.text], + [SHKFormFieldSettings label:SHKLocalizedString(@"Shared") key:@"shared" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], nil]; return nil; @@ -167,7 +167,7 @@ - (void)sendFinished:(SHKRequest *)aRequest } } - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was an error saving to Pinboard")]]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"There was an error saving to Pinboard")]]; } @end diff --git a/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m b/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m index 1110b7fc..c9e42584 100644 --- a/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m +++ b/Classes/ShareKit/Sharers/Services/Read It Later/SHKReadItLater.m @@ -63,14 +63,14 @@ - (BOOL)shouldAutoShare + (NSString *)authorizationFormCaption { - return SKLocalizedString(@"Create a free account at Readitlaterlist.com"); + return SHKLocalizedString(@"Create a free account at %@", @"Readitlaterlist.com"); } - (void)authorizationFormValidate:(SHKFormController *)form { // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -102,10 +102,10 @@ - (void)authFinished:(SHKRequest *)aRequest else { - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Login Error") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Login Error") message:[request.headers objectForKey:@"X-Error"] delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } } @@ -119,8 +119,8 @@ - (NSArray *)shareFormFieldsForType:(SHKShareType)type { if (type == SHKShareTypeURL) return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], - [SHKFormFieldSettings label:SKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], + [SHKFormFieldSettings label:SHKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title], + [SHKFormFieldSettings label:SHKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], nil]; return nil; diff --git a/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m index 4f8d355b..9a8402f4 100644 --- a/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m +++ b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m @@ -59,13 +59,13 @@ - (BOOL)shouldAutoShare{ #pragma mark Authorization - (NSString *)authorizationFormCaption{ - return SKLocalizedString(@"Set up a free account at http://tumblr.com"); + return SHKLocalizedString(@"Set up a free account at %@", @"Tumblr.com"); } - (void)authorizationFormValidate:(SHKFormController *)form{ // Display an activity indicator if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Logging In...")]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Logging In...")]; // Authorize the user through the server @@ -94,14 +94,14 @@ - (void)authFinished:(SHKRequest *)aRequest{ else { NSString *errorMessage = nil; if (aRequest.response.statusCode == 403) - errorMessage = SKLocalizedString(@"Invalid email or password."); + errorMessage = SHKLocalizedString(@"Invalid email or password."); else - errorMessage = SKLocalizedString(@"The service encountered an error. Please try again later."); + errorMessage = SHKLocalizedString(@"The service encountered an error. Please try again later."); - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Login Error") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Login Error") message:errorMessage delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; } } @@ -110,11 +110,11 @@ - (void)authFinished:(SHKRequest *)aRequest{ #pragma mark Authorize form - (NSArray *)authorizationFormFields{ return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Email") + [SHKFormFieldSettings label:SHKLocalizedString(@"Email") key:@"email" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:SKLocalizedString(@"Password") + [SHKFormFieldSettings label:SHKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], @@ -126,32 +126,32 @@ - (NSArray *)authorizationFormFields{ - (NSArray *)shareFormFieldsForType:(SHKShareType)type{ NSMutableArray *baseArray = [NSMutableArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Tags") + [SHKFormFieldSettings label:SHKLocalizedString(@"Tags") key:@"tags" type:SHKFormFieldTypeText start:item.tags], - [SHKFormFieldSettings label:SKLocalizedString(@"Slug") + [SHKFormFieldSettings label:SHKLocalizedString(@"Slug") key:@"slug" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:SKLocalizedString(@"Private") + [SHKFormFieldSettings label:SHKLocalizedString(@"Private") key:@"private" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], - [SHKFormFieldSettings label:SKLocalizedString(@"Send to Twitter") + [SHKFormFieldSettings label:SHKLocalizedString(@"Send to Twitter") key:@"twitter" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOff], nil ]; if([item shareType] == SHKShareTypeImage){ - [baseArray insertObject:[SHKFormFieldSettings label:SKLocalizedString(@"Caption") + [baseArray insertObject:[SHKFormFieldSettings label:SHKLocalizedString(@"Caption") key:@"caption" type:SHKFormFieldTypeText start:nil] atIndex:0]; }else{ - [baseArray insertObject:[SHKFormFieldSettings label:SKLocalizedString(@"Title") + [baseArray insertObject:[SHKFormFieldSettings label:SHKLocalizedString(@"Title") key:@"title" type:SHKFormFieldTypeText start:item.title] @@ -310,15 +310,15 @@ - (BOOL)send{ - (void)sendFinished:(SHKRequest *)aRequest{ if (!aRequest.success) { if (aRequest.response.statusCode == 403) { - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"Invalid email or password.")] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"Invalid email or password.")] shouldRelogin:YES]; return; } else if (aRequest.response.statusCode == 500) { - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"The service encountered an error. Please try again later.")]]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"The service encountered an error. Please try again later.")]]; return; } - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a sending your post to Tumblr.")]]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"There was a sending your post to Tumblr.")]]; return; } @@ -352,14 +352,14 @@ - (void)finish{ [self sendDidFinish]; }else{ if(response.statusCode == 403) { - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"Invalid email or password.")] shouldRelogin:YES]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"Invalid email or password.")] shouldRelogin:YES]; return; } else if (response.statusCode == 500) { - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"The service encountered an error. Please try again later.")]]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"The service encountered an error. Please try again later.")]]; return; } - [self sendDidFailWithError:[SHK error:SKLocalizedString(@"There was a sending your post to Tumblr.")]]; + [self sendDidFailWithError:[SHK error:SHKLocalizedString(@"There was a sending your post to Tumblr.")]]; } } diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index fa466848..8dbf6aed 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -115,7 +115,7 @@ - (void)promptAuthorization + (NSString *)authorizationFormCaption { - return SKLocalizedString(@"Create a free account at Twitter.com"); + return SHKLocalizedString(@"Create a free account at %@", @"Twitter.com"); } + (NSArray *)authorizationFormFields @@ -124,9 +124,9 @@ + (NSArray *)authorizationFormFields return [super authorizationFormFields]; return [NSArray arrayWithObjects: - [SHKFormFieldSettings label:SKLocalizedString(@"Username") key:@"username" type:SHKFormFieldTypeText start:nil], - [SHKFormFieldSettings label:SKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], - [SHKFormFieldSettings label:[NSString stringWithFormat:SKLocalizedString(@"Follow %@"),SHKTwitterUsername] key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], + [SHKFormFieldSettings label:SHKLocalizedString(@"Username") key:@"username" type:SHKFormFieldTypeText start:nil], + [SHKFormFieldSettings label:SHKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], + [SHKFormFieldSettings label:[NSString stringWithFormat:SHKLocalizedString(@"Follow %@"),SHKTwitterUsername] key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], nil]; } @@ -227,7 +227,7 @@ - (void)sendForm:(SHKTwitterForm *)form - (void)shortenURL { if (!quiet) - [[SHKActivityIndicator currentIndicator] displayActivity:SKLocalizedString(@"Shortening URL...")]; + [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Shortening URL...")]; self.request = [[[SHKRequest alloc] initWithURL:[NSURL URLWithString:[NSMutableString stringWithFormat:@"http://api.bit.ly/v3/shorten?login=%@&apikey=%@&longUrl=%@&format=txt", SHKBitLyLogin, @@ -250,10 +250,10 @@ - (void)shortenURLFinished:(SHKRequest *)aRequest if (result == nil || [NSURL URLWithString:result] == nil) { // TODO - better error message - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Shorten URL Error") - message:SKLocalizedString(@"We could not shorten the URL.") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Shorten URL Error") + message:SHKLocalizedString(@"We could not shorten the URL.") delegate:nil - cancelButtonTitle:SKLocalizedString(@"Continue") + cancelButtonTitle:SHKLocalizedString(@"Continue") otherButtonTitles:nil] autorelease] show]; [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.title, [item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] forKey:@"status"]; diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.h b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.h index b31119d8..99cb3776 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.h +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.h @@ -41,4 +41,6 @@ @property (nonatomic, retain) UILabel *counter; @property BOOL hasAttachment; +- (void)layoutCounter; + @end diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m index a64d1cd2..382f7331 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m @@ -1,4 +1,4 @@ - // +// // SHKTwitterForm.m // ShareKit // @@ -53,7 +53,7 @@ - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil target:self action:@selector(cancel)]; - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:SKLocalizedString(@"Send to Twitter") + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Send to Twitter" style:UIBarButtonItemStyleDone target:self action:@selector(save)]; @@ -114,22 +114,37 @@ - (void)keyboardWillShow:(NSNotification *)notification // 3.2 and above /*if (UIKeyboardFrameEndUserInfoKey) - { - [[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrame]; - if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) - keyboardHeight = keyboardFrame.size.height; - else - keyboardHeight = keyboardFrame.size.width; - } - - // < 3.2 - else - {*/ - [[notification.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame]; - keyboardHeight = keyboardFrame.size.height; + { + [[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrame]; + if ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) + keyboardHeight = keyboardFrame.size.height; + else + keyboardHeight = keyboardFrame.size.width; + } + + // < 3.2 + else + {*/ + [[notification.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue:&keyboardFrame]; + keyboardHeight = keyboardFrame.size.height; //} - - textView.frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height-keyboardHeight); + + // Find the bottom of the screen (accounting for keyboard overlay) + // This is pretty much only for pagesheet's on the iPad + UIInterfaceOrientation orient = [[UIApplication sharedApplication] statusBarOrientation]; + BOOL inLandscape = orient == UIInterfaceOrientationLandscapeLeft || orient == UIInterfaceOrientationLandscapeRight; + BOOL upsideDown = orient == UIInterfaceOrientationPortraitUpsideDown || orient == UIInterfaceOrientationLandscapeRight; + + CGPoint topOfViewPoint = [self.view convertPoint:CGPointZero toView:nil]; + CGFloat topOfView = inLandscape ? topOfViewPoint.x : topOfViewPoint.y; + + CGFloat screenHeight = inLandscape ? [[UIScreen mainScreen] applicationFrame].size.width : [[UIScreen mainScreen] applicationFrame].size.height; + + CGFloat distFromBottom = screenHeight - ((upsideDown ? screenHeight - topOfView : topOfView ) + self.view.bounds.size.height) + ([UIApplication sharedApplication].statusBarHidden || upsideDown ? 0 : 20); + CGFloat maxViewHeight = self.view.bounds.size.height - keyboardHeight + distFromBottom; + + textView.frame = CGRectMake(0,0,self.view.bounds.size.width,maxViewHeight); + [self layoutCounter]; } #pragma mark - @@ -138,10 +153,7 @@ - (void)updateCounter { if (counter == nil) { - self.counter = [[UILabel alloc] initWithFrame:CGRectMake(textView.bounds.size.width-150-15, - textView.bounds.size.height-15-9, - 150, - 15)]; + self.counter = [[UILabel alloc] initWithFrame:CGRectZero]; counter.backgroundColor = [UIColor clearColor]; counter.opaque = NO; counter.font = [UIFont boldSystemFontOfSize:14]; @@ -151,6 +163,7 @@ - (void)updateCounter counter.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin; [self.view addSubview:counter]; + [self layoutCounter]; [counter release]; } @@ -160,6 +173,14 @@ - (void)updateCounter counter.textColor = count >= 0 ? [UIColor blackColor] : [UIColor redColor]; } +- (void)layoutCounter +{ + counter.frame = CGRectMake(textView.bounds.size.width-150-15, + textView.bounds.size.height-15-9, + 150, + 15); +} + - (void)textViewDidBeginEditing:(UITextView *)textView { [self updateCounter]; @@ -186,24 +207,24 @@ - (void)save { if (textView.text.length > (hasAttachment?115:140)) { - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Message is too long") - message:SKLocalizedString(@"Twitter posts can only be 140 characters in length.") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Message is too long") + message:SHKLocalizedString(@"Twitter posts can only be 140 characters in length.") delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; return; } else if (textView.text.length == 0) { - [[[[UIAlertView alloc] initWithTitle:SKLocalizedString(@"Message is empty") - message:SKLocalizedString(@"You must enter a message in order to post.") + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Message is empty") + message:SHKLocalizedString(@"You must enter a message in order to post.") delegate:nil - cancelButtonTitle:SKLocalizedString(@"Close") + cancelButtonTitle:SHKLocalizedString(@"Close") otherButtonTitles:nil] autorelease] show]; return; } - + [(SHKTwitter *)delegate sendForm:self]; [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; diff --git a/Classes/ShareKit/UI/SHKActionSheet.h b/Classes/ShareKit/UI/SHKActionSheet.h index 86e49301..a9db9da5 100644 --- a/Classes/ShareKit/UI/SHKActionSheet.h +++ b/Classes/ShareKit/UI/SHKActionSheet.h @@ -41,6 +41,5 @@ + (SHKActionSheet *)actionSheetForType:(SHKShareType)type; + (SHKActionSheet *)actionSheetForItem:(SHKItem *)i; -- (void)actionSheet:(SHKActionSheet *)as clickedButtonAtIndex:(NSInteger)buttonIndex; @end \ No newline at end of file diff --git a/Classes/ShareKit/UI/SHKActionSheet.m b/Classes/ShareKit/UI/SHKActionSheet.m index c0ee423b..47d73101 100644 --- a/Classes/ShareKit/UI/SHKActionSheet.m +++ b/Classes/ShareKit/UI/SHKActionSheet.m @@ -44,37 +44,30 @@ - (void)dealloc + (SHKActionSheet *)actionSheetForType:(SHKShareType)type { - SHKActionSheet *as = [[SHKActionSheet alloc] initWithTitle:SKLocalizedString(@"Share") + SHKActionSheet *as = [[SHKActionSheet alloc] initWithTitle:SHKLocalizedString(@"Share") delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil]; as.item = [[[SHKItem alloc] init] autorelease]; as.item.shareType = type; - as.delegate = as; as.sharers = [SHK favoriteSharersForType:type]; // Add buttons for each favoriate sharer - NSMutableArray *activeSharer = [NSMutableArray array]; id class; for(NSString *sharerId in as.sharers) { class = NSClassFromString(sharerId); - if ([class canShare]) { + if ([class canShare]) [as addButtonWithTitle: [class sharerTitle] ]; - [activeSharer addObject:sharerId]; - } } - - // filter out sharers that cannot share - as.sharers = activeSharer; // Add More button - [as addButtonWithTitle:SKLocalizedString(@"More...")]; + [as addButtonWithTitle:SHKLocalizedString(@"More...")]; // Add Cancel button - [as addButtonWithTitle:SKLocalizedString(@"Cancel")]; + [as addButtonWithTitle:SHKLocalizedString(@"Cancel")]; as.cancelButtonIndex = as.numberOfButtons -1; return [as autorelease]; @@ -87,22 +80,24 @@ + (SHKActionSheet *)actionSheetForItem:(SHKItem *)i return as; } -- (void)actionSheet:(SHKActionSheet *)as clickedButtonAtIndex:(NSInteger)buttonIndex +- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated { // Sharers - if (buttonIndex >= 0 && buttonIndex < as.sharers.count) + if (buttonIndex >= 0 && buttonIndex < sharers.count) { - [objc_getClass([[as.sharers objectAtIndex:buttonIndex] UTF8String]) performSelector:@selector(shareItem:) withObject:item]; + [NSClassFromString([sharers objectAtIndex:buttonIndex]) performSelector:@selector(shareItem:) withObject:item]; } // More - else if (buttonIndex == as.sharers.count) + else if (buttonIndex == sharers.count) { SHKShareMenu *shareMenu = [[SHKCustomShareMenu alloc] initWithStyle:UITableViewStyleGrouped]; - shareMenu.item = as.item; + shareMenu.item = item; [[SHK currentHelper] showViewController:shareMenu]; [shareMenu release]; } + + [super dismissWithClickedButtonIndex:buttonIndex animated:animated]; } @end \ No newline at end of file diff --git a/Classes/ShareKit/UI/SHKFormFieldCell.h b/Classes/ShareKit/UI/SHKFormFieldCell.h index 4f86115c..803026cf 100644 --- a/Classes/ShareKit/UI/SHKFormFieldCell.h +++ b/Classes/ShareKit/UI/SHKFormFieldCell.h @@ -48,7 +48,7 @@ @property (nonatomic) CGFloat labelWidth; -@property (nonatomic, retain) UITextField *textField; +@property (nonatomic, retain, getter=getTextField) UITextField *textField; @property (nonatomic, retain) UISwitch *toggle; @property (nonatomic, retain) NSString *tmpValue; diff --git a/Classes/ShareKit/UI/SHKFormFieldCell.m b/Classes/ShareKit/UI/SHKFormFieldCell.m index f4b330ed..f91b8e06 100644 --- a/Classes/ShareKit/UI/SHKFormFieldCell.m +++ b/Classes/ShareKit/UI/SHKFormFieldCell.m @@ -48,29 +48,33 @@ - (void)dealloc [super dealloc]; } +- (UITextField *)getTextField +{ + if (textField == nil) + { + self.textField = [[UITextField alloc] initWithFrame:CGRectMake(0,0,0,25)]; + textField.clearsOnBeginEditing = NO; + textField.returnKeyType = UIReturnKeyDone; + textField.font = [UIFont systemFontOfSize:17]; + textField.textColor = [UIColor darkGrayColor]; + textField.autocapitalizationType = UITextAutocapitalizationTypeNone; + textField.delegate = form; + [self.contentView addSubview:textField]; + [textField release]; + + [self setValue:tmpValue]; + } + return textField; +} + - (void)layoutSubviews { [super layoutSubviews]; if (settings.type == SHKFormFieldTypeText || settings.type == SHKFormFieldTypePassword) { - if (textField == nil) - { - self.textField = [[UITextField alloc] initWithFrame:CGRectMake(0,0,0,25)]; - textField.clearsOnBeginEditing = NO; - textField.returnKeyType = UIReturnKeyDone; - textField.font = [UIFont systemFontOfSize:17]; - textField.textColor = [UIColor darkGrayColor]; - textField.autocapitalizationType = UITextAutocapitalizationTypeNone; - textField.delegate = form; - [self.contentView addSubview:textField]; - [textField release]; - - [self setValue:tmpValue]; - } + self.textField.secureTextEntry = settings.type == SHKFormFieldTypePassword; - textField.secureTextEntry = settings.type == SHKFormFieldTypePassword; - textField.frame = CGRectMake(labelWidth + SHK_FORM_CELL_PAD_LEFT, 2 + round(self.contentView.bounds.size.height/2 - textField.bounds.size.height/2), self.contentView.bounds.size.width - SHK_FORM_CELL_PAD_RIGHT - SHK_FORM_CELL_PAD_LEFT - labelWidth, @@ -106,7 +110,7 @@ - (void)setSelected:(BOOL)selected animated:(BOOL)animated { // don't actually select the row //[super setSelected:selected animated:animated]; - + if (selected) [textField becomeFirstResponder]; diff --git a/Classes/ShareKit/UI/SHKShareMenu.m b/Classes/ShareKit/UI/SHKShareMenu.m index 267f9124..161175fc 100644 --- a/Classes/ShareKit/UI/SHKShareMenu.m +++ b/Classes/ShareKit/UI/SHKShareMenu.m @@ -52,13 +52,13 @@ - (id)initWithStyle:(UITableViewStyle)style { if (self = [super initWithStyle:style]) { - self.title = SKLocalizedString(@"Share"); + self.title = SHKLocalizedString(@"Share"); self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:SKLocalizedString(@"Edit") + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:SHKLocalizedString(@"Edit") style:UIBarButtonItemStyleBordered target:self action:@selector(edit)]; @@ -263,7 +263,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath else { - [objc_getClass([[rowData objectForKey:@"className"] UTF8String]) shareItem:item]; + [NSClassFromString([rowData objectForKey:@"className"]) shareItem:item]; [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; } @@ -279,10 +279,10 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte if ([[tableData objectAtIndex:section] count]) { if (section == 0) - return SKLocalizedString(@"Actions"); + return SHKLocalizedString(@"Actions"); else if (section == 1) - return SKLocalizedString(@"Services"); + return SHKLocalizedString(@"Services"); } return nil; @@ -314,7 +314,7 @@ - (void)save [self.tableView setEditing:NO animated:YES]; [self rebuildTableDataAnimated:YES]; - [self.navigationItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:SKLocalizedString(@"Edit") + [self.navigationItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:SHKLocalizedString(@"Edit") style:UIBarButtonItemStyleBordered target:self action:@selector(edit)] autorelease] animated:YES]; diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index 3a1b0a7a..ebe4b80b 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28F335F01007B36200424DE2 /* RootViewController.xib */; }; 4312CF7C11CB33E200E61D7A /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4312CF7B11CB33E200E61D7A /* MessageUI.framework */; }; 43150A8D11E78697008C6B68 /* SHKInstapaper.m in Sources */ = {isa = PBXBuildFile; fileRef = 43150A8C11E78697008C6B68 /* SHKInstapaper.m */; }; + 432B13FC11FF45CF00291B37 /* ShareKit.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 432B13FB11FF45CF00291B37 /* ShareKit.bundle */; }; + 432B147C11FF4B0700291B37 /* SHKPhotoAlbum.m in Sources */ = {isa = PBXBuildFile; fileRef = 432B147B11FF4B0700291B37 /* SHKPhotoAlbum.m */; }; 43A5370011DBE3B9004A1712 /* SHKOAuthSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */; }; 43A5370111DBE3B9004A1712 /* SHKSharer.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367711DBE3B9004A1712 /* SHKSharer.m */; }; 43A5370211DBE3B9004A1712 /* UIWebView+SHK.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5367A11DBE3B9004A1712 /* UIWebView+SHK.m */; }; @@ -81,11 +83,11 @@ 43A5383B11DBE493004A1712 /* ShareKitAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */; }; 43A53C0911DC07A9004A1712 /* SHKCustomShareMenuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */; }; 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */; }; + 43B934B511FE682600C9D3F3 /* SHKFBStreamDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */; }; 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */; }; 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */; }; 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; 43EF406E11D3FFF800B1F700 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43EF406D11D3FFF800B1F700 /* Security.framework */; }; - 7882FB2511F5005F006E7742 /* ShareKit.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 7882FB2411F5005F006E7742 /* ShareKit.bundle */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -100,6 +102,9 @@ 4312CF7B11CB33E200E61D7A /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; 43150A8B11E78697008C6B68 /* SHKInstapaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKInstapaper.h; sourceTree = ""; }; 43150A8C11E78697008C6B68 /* SHKInstapaper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKInstapaper.m; sourceTree = ""; }; + 432B13FB11FF45CF00291B37 /* ShareKit.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = ShareKit.bundle; path = ../ShareKit.bundle; sourceTree = ""; }; + 432B147A11FF4B0700291B37 /* SHKPhotoAlbum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKPhotoAlbum.h; sourceTree = ""; }; + 432B147B11FF4B0700291B37 /* SHKPhotoAlbum.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKPhotoAlbum.m; sourceTree = ""; }; 43A5367411DBE3B9004A1712 /* SHKOAuthSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKOAuthSharer.h; sourceTree = ""; }; 43A5367511DBE3B9004A1712 /* SHKOAuthSharer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKOAuthSharer.m; sourceTree = ""; }; 43A5367611DBE3B9004A1712 /* SHKSharer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKSharer.h; sourceTree = ""; }; @@ -232,12 +237,13 @@ 43A53C0811DC07A9004A1712 /* SHKCustomShareMenuCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenuCell.m; sourceTree = ""; }; 43A53C1011DC08B1004A1712 /* SHKCustomShareMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKCustomShareMenu.h; sourceTree = ""; }; 43A53C1111DC08B1004A1712 /* SHKCustomShareMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKCustomShareMenu.m; sourceTree = ""; }; + 43B934B311FE682600C9D3F3 /* SHKFBStreamDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKFBStreamDialog.h; sourceTree = ""; }; + 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKFBStreamDialog.m; sourceTree = ""; }; 43C91D1C11EB963600F31FAE /* MainWindow-iPad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "MainWindow-iPad.xib"; path = "Resources-iPad/MainWindow-iPad.xib"; sourceTree = ""; }; 43C91DF311EBAE4800F31FAE /* SHKTumblr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKTumblr.h; sourceTree = ""; }; 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTumblr.m; sourceTree = ""; }; 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 43EF406D11D3FFF800B1F700 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; - 7882FB2411F5005F006E7742 /* ShareKit.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = ShareKit.bundle; sourceTree = SOURCE_ROOT; }; 8D1107310486CEB800E47090 /* ShareKit-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ShareKit-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -331,6 +337,15 @@ path = Instapaper; sourceTree = ""; }; + 432B147911FF4B0700291B37 /* Save to Album */ = { + isa = PBXGroup; + children = ( + 432B147A11FF4B0700291B37 /* SHKPhotoAlbum.h */, + 432B147B11FF4B0700291B37 /* SHKPhotoAlbum.m */, + ); + path = "Save to Album"; + sourceTree = ""; + }; 4362EB3311B9937300E3DB3A /* Example Project */ = { isa = PBXGroup; children = ( @@ -346,7 +361,6 @@ 43A5383311DBE493004A1712 /* RootViewController.m */, 43A5383411DBE493004A1712 /* ShareKitAppDelegate.h */, 43A5383511DBE493004A1712 /* ShareKitAppDelegate.m */, - 7882FB2411F5005F006E7742 /* ShareKit.bundle */, ); name = "Example Project"; sourceTree = ""; @@ -377,6 +391,7 @@ 43A5367311DBE3B9004A1712 /* Base Sharer Classes */, 43A5367811DBE3B9004A1712 /* Categories */, 43A5367B11DBE3B9004A1712 /* Helpers */, + 432B13FB11FF45CF00291B37 /* ShareKit.bundle */, ); path = Core; sourceTree = ""; @@ -509,6 +524,7 @@ 43A536B711DBE3B9004A1712 /* Copy */, 43A536BA11DBE3B9004A1712 /* Email */, 43A536BD11DBE3B9004A1712 /* Open in Safari */, + 432B147911FF4B0700291B37 /* Save to Album */, ); path = Actions; sourceTree = ""; @@ -570,6 +586,8 @@ 43A536C511DBE3B9004A1712 /* FBConnect */, 43A536DC11DBE3B9004A1712 /* SHKFacebook.h */, 43A536DD11DBE3B9004A1712 /* SHKFacebook.m */, + 43B934B311FE682600C9D3F3 /* SHKFBStreamDialog.h */, + 43B934B411FE682600C9D3F3 /* SHKFBStreamDialog.m */, ); path = Facebook; sourceTree = ""; @@ -730,6 +748,7 @@ isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ShareKit" */; compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, @@ -759,7 +778,7 @@ 43A5382811DBE480004A1712 /* example.pdf in Resources */, 43A5382911DBE480004A1712 /* sanFran.jpg in Resources */, 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */, - 7882FB2511F5005F006E7742 /* ShareKit.bundle in Resources */, + 432B13FC11FF45CF00291B37 /* ShareKit.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -835,6 +854,8 @@ 43A53C1211DC08B1004A1712 /* SHKCustomShareMenu.m in Sources */, 43150A8D11E78697008C6B68 /* SHKInstapaper.m in Sources */, 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */, + 43B934B511FE682600C9D3F3 /* SHKFBStreamDialog.m in Sources */, + 432B147C11FF4B0700291B37 /* SHKPhotoAlbum.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -854,7 +875,7 @@ INFOPLIST_FILE = "ShareKit-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 3.2; PRODUCT_NAME = ShareKit; - SDKROOT = iphoneos4.0; + SDKROOT = iphoneos4.1; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -870,7 +891,7 @@ INFOPLIST_FILE = "ShareKit-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 3.2; PRODUCT_NAME = ShareKit; - SDKROOT = iphoneos4.0; + SDKROOT = iphoneos4.1; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -886,7 +907,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 3.1; PREBINDING = NO; - SDKROOT = iphoneos4.0; + SDKROOT = iphoneos4.1; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -902,7 +923,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 3.1; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; PREBINDING = NO; - SDKROOT = iphoneos4.0; + SDKROOT = iphoneos4.1; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; From 692b98a789728a668d76387bd30a297df9ecf871 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Tue, 27 Jul 2010 16:55:33 -0700 Subject: [PATCH 21/50] Version 0.2.0 -SHKTwitter: Don't attempt to shorten while offline -SHKTwitter: Crash on @"Follow %@" format string -SHKEmail: Added 'Sent with ...' -SHKDelicious: Titles were double encoded -SHK: SHKStringOrBlank function -Updated FBConnect to version 1.3.0 --- Classes/ShareKit/Core/SHK.h | 3 +- Classes/ShareKit/Core/SHK.m | 4 + Classes/ShareKit/SHKConfig.h | 2 +- .../ShareKit/Sharers/Actions/Email/SHKMail.m | 6 + .../Sharers/Services/Delicious/SHKDelicious.m | 28 +- .../Services/Facebook/FBConnect/FBConnect.h | 3 +- .../Facebook/FBConnect/FBConnectGlobal.h | 5 + .../Facebook/FBConnect/FBConnectGlobal.m | 12 + .../Services/Facebook/FBConnect/FBDialog.m | 38 +- .../Facebook/FBConnect/FBLoginButton.m | 34 ++ .../Facebook/FBConnect/FBLoginDialog.m | 10 +- .../Services/Facebook/FBConnect/FBRequest.h | 24 +- .../Services/Facebook/FBConnect/FBRequest.m | 476 +++++++++--------- .../Services/Facebook/FBConnect/FBSession.h | 15 + .../Services/Facebook/FBConnect/FBSession.m | 33 +- .../Facebook/FBConnect/FBXMLHandler.h | 2 +- .../Facebook/FBConnect/FBXMLHandler.m | 6 +- .../Sharers/Services/Twitter/SHKTwitter.m | 9 +- 18 files changed, 413 insertions(+), 297 deletions(-) diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index 5a5daf92..5c90206a 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -25,7 +25,7 @@ // // -#define SHK_VERSION @"0.2.0b1" +#define SHK_VERSION @"0.2.0" #import #import "SHKConfig.h" @@ -121,6 +121,7 @@ @end +NSString * SHKStringOrBlank(NSString * value); NSString * SHKEncode(NSString * value); NSString * SHKEncodeURL(NSURL * value); NSString* SHKLocalizedString(NSString* key, ...); diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m index b9606f85..9eb1ea7c 100644 --- a/Classes/ShareKit/Core/SHK.m +++ b/Classes/ShareKit/Core/SHK.m @@ -531,6 +531,10 @@ + (BOOL)connected @end +NSString * SHKStringOrBlank(NSString * value) +{ + return value == nil ? @"" : value; +} NSString * SHKEncode(NSString * value) { diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 8e291f7e..43906421 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -141,6 +141,6 @@ These settings can be left as is. This only need to be changed for uber custom installs. */ -#define SHK_MAX_FAV_COUNT 4 +#define SHK_MAX_FAV_COUNT 3 #define SHK_FAVS_PREFIX_KEY @"SHK_FAVS_" #define SHK_AUTH_PREFIX @"SHK_AUTH_" \ No newline at end of file diff --git a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m index bab1a310..1f69b187 100644 --- a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m +++ b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m @@ -148,6 +148,12 @@ - (BOOL)sendMail if (item.image) [mailController addAttachmentData:UIImageJPEGRepresentation(item.image, 1) mimeType:@"image/jpeg" fileName:@"Image.jpg"]; + // fallback + if (body == nil) + body = @""; + + // sig + body = [body stringByAppendingFormat:@"

Sent from %@", SHKMyAppName]; // save changes to body [item setCustomValue:body forKey:@"body"]; diff --git a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m index 5dfb2d99..59e8b10d 100644 --- a/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m +++ b/Classes/ShareKit/Sharers/Services/Delicious/SHKDelicious.m @@ -143,28 +143,24 @@ - (BOOL)send [oRequest setHTTPMethod:@"GET"]; - OARequestParameter *urlParam = [[OARequestParameter alloc] initWithName:@"url" - value:SHKEncodeURL(item.URL)]; - OARequestParameter *descParam = [[OARequestParameter alloc] initWithName:@"description" - value:SHKEncode(item.title)]; + OARequestParameter *urlParam = [OARequestParameter requestParameterWithName:@"url" + value:[item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - OARequestParameter *tagsParam = [[OARequestParameter alloc] initWithName:@"tags" - value:SHKEncode(item.tags)]; + OARequestParameter *descParam = [OARequestParameter requestParameterWithName:@"description" + value:SHKStringOrBlank(item.title)]; - OARequestParameter *extendedParam = [[OARequestParameter alloc] initWithName:@"extended" - value:SHKEncode(item.text)]; + OARequestParameter *tagsParam = [OARequestParameter requestParameterWithName:@"tags" + value:SHKStringOrBlank(item.tags)]; + + OARequestParameter *extendedParam = [OARequestParameter requestParameterWithName:@"extended" + value:SHKStringOrBlank(item.text)]; + + OARequestParameter *sharedParam = [OARequestParameter requestParameterWithName:@"shared" + value:[item customBoolForSwitchKey:@"shared"]?@"yes":@"no"]; - OARequestParameter *sharedParam = [[OARequestParameter alloc] initWithName:@"shared" - value:[item customBoolForSwitchKey:@"shared"]?@"yes":@"no"]; - [oRequest setParameters:[NSArray arrayWithObjects:descParam, extendedParam, sharedParam, tagsParam, urlParam, nil]]; - [urlParam release]; - [descParam release]; - [tagsParam release]; - [extendedParam release]; - [sharedParam release]; OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest delegate:self diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.h index 15c2a95b..80f5f0ff 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnect.h @@ -19,5 +19,4 @@ #import "FBLoginButton.h" #import "FBLoginDialog.h" #import "FBPermissionDialog.h" -#import "FBFeedDialog.h" -#import "FBStreamDialog.h" \ No newline at end of file +#import "FBStreamDialog.h" diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.h index 47018157..99d51eee 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.h @@ -19,6 +19,10 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// +extern const NSString* kFB_SDK_VersionNumber; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + #ifdef DEBUG #define FBLOG #define FBLOG2 @@ -211,3 +215,4 @@ typedef unsigned long long FBID; NSMutableArray* FBCreateNonRetainingArray(); +BOOL FBIsDeviceIPad(); diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m index ff85788d..77ec5ca4 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBConnectGlobal.m @@ -16,6 +16,8 @@ #import "FBConnectGlobal.h" +const NSString* kFB_SDK_VersionNumber = @"iphone/1.3.0"; + /////////////////////////////////////////////////////////////////////////////////////////////////// // private @@ -31,3 +33,13 @@ void ReleaseNoOp(CFAllocatorRef allocator, const void *value) { } callbacks.release = ReleaseNoOp; return (NSMutableArray*)CFArrayCreateMutable(nil, 0, &callbacks); } + + +BOOL FBIsDeviceIPad() { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200 + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + return YES; + } +#endif + return NO; +} diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m index 4d10bbf5..fd119f25 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBDialog.m @@ -156,10 +156,16 @@ - (void)sizeToFitOrientation:(BOOL)transform { CGPoint center = CGPointMake( frame.origin.x + ceil(frame.size.width/2), frame.origin.y + ceil(frame.size.height/2)); - - CGFloat width = frame.size.width - kPadding * 2; - CGFloat height = frame.size.height - kPadding * 2; - + + CGFloat scale_factor = 1.0f; + if (FBIsDeviceIPad()) { + // On the iPad the dialog's dimensions should only be 60% of the screen's + scale_factor = 0.6f; + } + + CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2; + CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2; + _orientation = [UIApplication sharedApplication].statusBarOrientation; if (UIInterfaceOrientationIsLandscape(_orientation)) { self.frame = CGRectMake(kPadding, kPadding, height, width); @@ -319,17 +325,22 @@ - (id)initWithSession:(FBSession*)session { [_closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; [_closeButton addTarget:self action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside]; - _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12]; - _closeButton.showsTouchWhenHighlighted = YES; + if ([_closeButton respondsToSelector:@selector(titleLabel)]) { + _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12]; + } else { // This triggers a deprecation warning but at least it will work on OS 2.x + _closeButton.font = [UIFont boldSystemFontOfSize:12]; + } + _closeButton.showsTouchWhenHighlighted = YES; _closeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin; [self addSubview:_closeButton]; + CGFloat titleLabelFontSize = (FBIsDeviceIPad() ? 18 : 14); _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; _titleLabel.text = kDefaultTitle; _titleLabel.backgroundColor = [UIColor clearColor]; _titleLabel.textColor = [UIColor whiteColor]; - _titleLabel.font = [UIFont boldSystemFontOfSize:14]; + _titleLabel.font = [UIFont boldSystemFontOfSize:titleLabelFontSize]; _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin; [self addSubview:_titleLabel]; @@ -444,17 +455,26 @@ - (void)deviceOrientationDidChange:(void*)object { // UIKeyboardNotifications - (void)keyboardWillShow:(NSNotification*)notification { + if (FBIsDeviceIPad()) { + // On the iPad the screen is large enough that we don't need to + // resize the dialog to accomodate the keyboard popping up + return; + } + UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; if (UIInterfaceOrientationIsLandscape(orientation)) { _webView.frame = CGRectInset(_webView.frame, - - (kPadding + kBorderWidth), - - (kPadding + kBorderWidth) - _titleLabel.frame.size.height); + -(kPadding + kBorderWidth), + -(kPadding + kBorderWidth) - _titleLabel.frame.size.height); } _showingKeyboard = YES; } - (void)keyboardWillHide:(NSNotification*)notification { + if (FBIsDeviceIPad()) { + return; + } UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; if (UIInterfaceOrientationIsLandscape(orientation)) { _webView.frame = CGRectInset(_webView.frame, diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m index 92bfb27a..06b5818b 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginButton.m @@ -17,8 +17,12 @@ #import "FBLoginButton.h" #import "FBLoginDialog.h" +#import + /////////////////////////////////////////////////////////////////////////////////////////////////// +static UIAccessibilityTraits *traitImage = nil, *traitButton = nil; + @implementation FBLoginButton @synthesize session = _session, style = _style; @@ -26,6 +30,14 @@ @implementation FBLoginButton /////////////////////////////////////////////////////////////////////////////////////////////////// // private ++ (void)initialize { + if (self == [FBLoginButton class]) { + // Try to load the accessibility trait values on OS 3.0 + traitImage = dlsym(RTLD_SELF, "UIAccessibilityTraitImage"); + traitButton = dlsym(RTLD_SELF, "UIAccessibilityTraitButton"); + } +} + - (UIImage*)buttonImage { if (_session.isConnected) { return [UIImage imageNamed:@"FBConnect.bundle/images/logout.png"]; @@ -139,6 +151,28 @@ - (void)sessionDidLogout:(FBSession*)session { [self updateImage]; } +/////////////////////////////////////////////////////////////////////////////////////////////////// +// UIAccessibility informal protocol (on 3.0 only) + +- (BOOL)isAccessibilityElement { + return YES; +} + +- (UIAccessibilityTraits)accessibilityTraits { + if (traitImage && traitButton) + return [super accessibilityTraits]|*traitImage|*traitButton; + else + return [super accessibilityTraits]; +} + +- (NSString *)accessibilityLabel { + if (_session.isConnected) { + return NSLocalizedString(@"Disconnect from Facebook", @"Accessibility label"); + } else { + return NSLocalizedString(@"Connect to Facebook", @"Accessibility label"); + } +} + /////////////////////////////////////////////////////////////////////////////////////////////////// // public diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m index 63058f3e..9d49f603 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBLoginDialog.m @@ -27,8 +27,6 @@ @implementation FBLoginDialog -//@synthesize session = _session; - /////////////////////////////////////////////////////////////////////////////////////////////////// // private @@ -78,9 +76,13 @@ - (void)load { } - (void)dialogWillDisappear { - [_webView stringByEvaluatingJavaScriptFromString:@"email.blur();"]; + [_webView stringByEvaluatingJavaScriptFromString:@"email.blur();"]; [_getSessionRequest cancel]; + + if (![_session isConnected]) { + [_session cancelLogin]; + } } - (void)dialogDidSucceed:(NSURL*)url { @@ -104,7 +106,7 @@ - (void)dialogDidSucceed:(NSURL*)url { - (void)request:(FBRequest*)request didLoad:(id)result { NSDictionary* object = result; - FBUID uid = [[object objectForKey:@"uid"] intValue]; + FBUID uid = [[object objectForKey:@"uid"] longLongValue]; NSString* sessionKey = [object objectForKey:@"session_key"]; NSString* sessionSecret = [object objectForKey:@"secret"]; NSTimeInterval expires = [[object objectForKey:@"expires"] floatValue]; diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h index 66950b61..1c5852b3 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.h @@ -6,13 +6,13 @@ * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 - + * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ +*/ #import "FBConnectGlobal.h" @@ -20,16 +20,16 @@ @class FBSession; @interface FBRequest : NSObject { - FBSession* _session; - id _delegate; - NSString* _url; - NSString* _method; - id _userInfo; - NSMutableDictionary* _params; - NSObject* _dataParam; - NSDate* _timestamp; - NSURLConnection* _connection; - NSMutableData* _responseText; + FBSession* _session; + id _delegate; + NSString* _url; + NSString* _method; + id _userInfo; + NSMutableDictionary* _params; + NSObject* _dataParam; + NSDate* _timestamp; + NSURLConnection* _connection; + NSMutableData* _responseText; } /** diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m index 08dcfc40..50dd54e5 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBRequest.m @@ -6,13 +6,13 @@ * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 - + * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ +*/ #import "FBRequest.h" #import "FBSession.h" @@ -34,345 +34,345 @@ @implementation FBRequest @synthesize delegate = _delegate, -url = _url, -method = _method, -params = _params, -dataParam = _dataParam, -userInfo = _userInfo, -timestamp = _timestamp; + url = _url, + method = _method, + params = _params, + dataParam = _dataParam, + userInfo = _userInfo, + timestamp = _timestamp; /////////////////////////////////////////////////////////////////////////////////////////////////// // class public + (FBRequest*)request { - return [self requestWithSession:[FBSession session]]; + return [self requestWithSession:[FBSession session]]; } + (FBRequest*)requestWithDelegate:(id)delegate { - return [self requestWithSession:[FBSession session] delegate:delegate]; + return [self requestWithSession:[FBSession session] delegate:delegate]; } + (FBRequest*)requestWithSession:(FBSession*)session { - return [[[FBRequest alloc] initWithSession:session] autorelease]; + return [[[FBRequest alloc] initWithSession:session] autorelease]; } + (FBRequest*)requestWithSession:(FBSession*)session delegate:(id)delegate { - FBRequest* request = [[[FBRequest alloc] initWithSession:session] autorelease]; - request.delegate = delegate; - return request; + FBRequest* request = [[[FBRequest alloc] initWithSession:session] autorelease]; + request.delegate = delegate; + return request; } /////////////////////////////////////////////////////////////////////////////////////////////////// // private - (NSString*)md5HexDigest:(NSString*)input { - const char* str = [input UTF8String]; - unsigned char result[CC_MD5_DIGEST_LENGTH]; - CC_MD5(str, strlen(str), result); - - NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2]; - for(int i = 0; i", _method ? _method : _url]; + return [NSString stringWithFormat:@"", _method ? _method : _url]; } ////////////////////////////////////////////////////////////////////////////////////////////////// // NSURLConnectionDelegate - + - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { - _responseText = [[NSMutableData alloc] init]; - - NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; - if ([_delegate respondsToSelector:@selector(request:didReceiveResponse:)]) { - [_delegate request:self didReceiveResponse:httpResponse]; - } + _responseText = [[NSMutableData alloc] init]; + + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; + if ([_delegate respondsToSelector:@selector(request:didReceiveResponse:)]) { + [_delegate request:self didReceiveResponse:httpResponse]; + } } -- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { - [_responseText appendData:data]; +-(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { + [_responseText appendData:data]; } - (NSCachedURLResponse*)connection:(NSURLConnection*)connection - willCacheResponse:(NSCachedURLResponse*)cachedResponse { - return nil; + willCacheResponse:(NSCachedURLResponse*)cachedResponse { + return nil; } -- (void)connectionDidFinishLoading:(NSURLConnection*)connection { - [self handleResponseData:_responseText]; - - [_responseText release]; - _responseText = nil; - [_connection release]; - _connection = nil; +-(void)connectionDidFinishLoading:(NSURLConnection*)connection { + [self handleResponseData:_responseText]; + + [_responseText release]; + _responseText = nil; + [_connection release]; + _connection = nil; } - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { - [self failWithError:error]; - - [_responseText release]; - _responseText = nil; - [_connection release]; - _connection = nil; + [self failWithError:error]; + + [_responseText release]; + _responseText = nil; + [_connection release]; + _connection = nil; } ////////////////////////////////////////////////////////////////////////////////////////////////// // public - (BOOL)loading { - return !!_connection; + return !!_connection; } - (void)call:(NSString*)method params:(NSDictionary*)params { - [self call:method params:params dataParam:nil]; + [self call:method params:params dataParam:nil]; } - (void)call:(NSString*)method params:(NSDictionary*)params dataParam:(NSData*)dataParam { - _url = [[self urlForMethod:method] retain]; - _method = [method copy]; - _params = params + _url = [[self urlForMethod:method] retain]; + _method = [method copy]; + _params = params ? [[NSMutableDictionary alloc] initWithDictionary:params] : [[NSMutableDictionary alloc] init]; - _dataParam = dataParam; - - [_params setObject:_method forKey:@"method"]; - [_params setObject:_session.apiKey forKey:@"api_key"]; - [_params setObject:kAPIVersion forKey:@"v"]; - [_params setObject:kAPIFormat forKey:@"format"]; + _dataParam = dataParam; + + [_params setObject:_method forKey:@"method"]; + [_params setObject:_session.apiKey forKey:@"api_key"]; + [_params setObject:kAPIVersion forKey:@"v"]; + [_params setObject:kAPIFormat forKey:@"format"]; + + if (![self isSpecialMethod]) { + [_params setObject:_session.sessionKey forKey:@"session_key"]; + [_params setObject:[self generateCallId] forKey:@"call_id"]; + + if (_session.sessionSecret) { + [_params setObject:@"1" forKey:@"ss"]; + } + } + + [_params setObject:[self generateSig] forKey:@"sig"]; - if (![self isSpecialMethod]) { - [_params setObject:_session.sessionKey forKey:@"session_key"]; - [_params setObject:[self generateCallId] forKey:@"call_id"]; - - if (_session.sessionSecret) { - [_params setObject:@"1" forKey:@"ss"]; - } - } - - [_params setObject:[self generateSig] forKey:@"sig"]; - - [_session send:self]; + [_session send:self]; } - (void)post:(NSString*)url params:(NSDictionary*)params { - _url = [url retain]; - _params = params + _url = [url retain]; + _params = params ? [[NSMutableDictionary alloc] initWithDictionary:params] : [[NSMutableDictionary alloc] init]; - - [_session send:self]; + + [_session send:self]; } - (void)cancel { - if (_connection) { - [_connection cancel]; - [_connection release]; - _connection = nil; - - if ([_delegate respondsToSelector:@selector(requestWasCancelled:)]) { - [_delegate requestWasCancelled:self]; - } - } + if (_connection) { + [_connection cancel]; + [_connection release]; + _connection = nil; + + if ([_delegate respondsToSelector:@selector(requestWasCancelled:)]) { + [_delegate requestWasCancelled:self]; + } + } } @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h index edbfd3d5..19b63fe3 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.h @@ -152,6 +152,11 @@ */ - (BOOL)resume; +/** + * Cancels a login (no-op if the login is already complete). + */ +- (void)cancelLogin; + /** * Ends the current session and deletes the uid, session key, and secret from disk. */ @@ -162,6 +167,11 @@ */ - (void)send:(FBRequest*)request; +/** + * Deletes all cookies belonging to facebook + */ +- (void)deleteFacebookCookies; + @end /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -175,6 +185,11 @@ @optional +/** + * Called when a user closes the login dialog without logging in. + */ +- (void)sessionDidNotLogin:(FBSession*)session; + /** * Called when a session is about to log out. */ diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m index 2855765f..c21f11bb 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBSession.m @@ -69,7 +69,7 @@ + (FBSession*)sessionForApplication:(NSString*)key getSessionProxy:(NSString*)ge - (void)save { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; if (_uid) { - [defaults setInteger:_uid forKey:@"FBUserId"]; + [defaults setObject:[NSNumber numberWithLongLong:_uid] forKey:@"FBUserId"]; } else { [defaults removeObjectForKey:@"FBUserId"]; } @@ -226,7 +226,7 @@ - (void)begin:(FBUID)uid sessionKey:(NSString*)sessionKey - (BOOL)resume { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - FBUID uid = [defaults integerForKey:@"FBUserId"]; + FBUID uid = [[defaults objectForKey:@"FBUserId"] longLongValue]; if (uid) { NSDate* expirationDate = [defaults objectForKey:@"FBSessionExpires"]; if (!expirationDate || [expirationDate timeIntervalSinceNow] > 0) { @@ -244,6 +244,16 @@ - (BOOL)resume { return NO; } +- (void)cancelLogin { + if (![self isConnected]) { + for (id delegate in _delegates) { + if ([delegate respondsToSelector:@selector(sessionDidNotLogin:)]) { + [delegate sessionDidNotLogin:self]; + } + } + } +} + - (void)logout { if (_sessionKey) { for (id delegate in _delegates) { @@ -252,13 +262,8 @@ - (void)logout { } } - // Remove cookies that UIWebView may have stored - NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - NSArray* facebookCookies = [cookies cookiesForURL: - [NSURL URLWithString:@"http://login.facebook.com"]]; - for (NSHTTPCookie* cookie in facebookCookies) { - [cookies deleteCookie:cookie]; - } + [self deleteFacebookCookies]; + _uid = 0; [_sessionKey release]; @@ -275,6 +280,7 @@ - (void)logout { } } } else { + [self deleteFacebookCookies]; [self unsave]; } } @@ -283,4 +289,13 @@ - (void)send:(FBRequest*)request { [self performRequest:request enqueue:YES]; } +- (void)deleteFacebookCookies { + NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray* facebookCookies = [cookies cookiesForURL: + [NSURL URLWithString:@"http://login.facebook.com"]]; + for (NSHTTPCookie* cookie in facebookCookies) { + [cookies deleteCookie:cookie]; + } +} + @end diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h index a60ef6ad..27b1607a 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.h @@ -16,7 +16,7 @@ #import "FBConnectGlobal.h" -@interface FBXMLHandler : NSObject { +@interface FBXMLHandler : NSObject { NSMutableArray* _stack; NSMutableArray* _nameStack; id _rootObject; diff --git a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m index d8b1f745..54de261f 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/FBConnect/FBXMLHandler.m @@ -100,8 +100,8 @@ - (void)dealloc { // NSXMLParserDelegate - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName - namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName - attributes:(NSDictionary *)attributeDict { + namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName + attributes:(NSDictionary *)attributeDict { [self flushCharacters]; id object = nil; @@ -124,7 +124,7 @@ - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { } - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName - namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { + namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { [self flushCharacters]; id object = [[[self topObject:NO] retain] autorelease]; diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index 8dbf6aed..5a128e8d 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -126,7 +126,7 @@ + (NSArray *)authorizationFormFields return [NSArray arrayWithObjects: [SHKFormFieldSettings label:SHKLocalizedString(@"Username") key:@"username" type:SHKFormFieldTypeText start:nil], [SHKFormFieldSettings label:SHKLocalizedString(@"Password") key:@"password" type:SHKFormFieldTypePassword start:nil], - [SHKFormFieldSettings label:[NSString stringWithFormat:SHKLocalizedString(@"Follow %@"),SHKTwitterUsername] key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], + [SHKFormFieldSettings label:SHKLocalizedString(@"Follow %@", SHKTwitterUsername) key:@"followMe" type:SHKFormFieldTypeSwitch start:SHKFormFieldSwitchOn], nil]; } @@ -226,6 +226,13 @@ - (void)sendForm:(SHKTwitterForm *)form - (void)shortenURL { + if (![SHK connected]) + { + [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.title, [item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] forKey:@"status"]; + [self showTwitterForm]; + return; + } + if (!quiet) [[SHKActivityIndicator currentIndicator] displayActivity:SHKLocalizedString(@"Shortening URL...")]; From bb42f4c3f7dcfa81f65489b9856af12c4091530e Mon Sep 17 00:00:00 2001 From: Victor Date: Sat, 14 Aug 2010 22:48:33 +0800 Subject: [PATCH 22/50] Add on/off for alphabetical ordering items in ShareMenu --- Classes/ShareKit/SHKConfig.h | 3 +++ Classes/ShareKit/UI/SHKShareMenu.m | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 43906421..9d0e809e 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -103,6 +103,9 @@ #define SHKModalPresentationStyle @"UIModalPresentationFormSheet" // See: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle #define SHKModalTransitionStyle @"UIModalTransitionStyleCoverVertical" // See: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle +// ShareMenu Ordering +#define SHKShareMenuAlphabeticalOrder 0 // Setting this to 1 will show list in Alphabetical Order, setting to 0 will follow the order in SHKShares.plist + /* UI Configuration : Advanced diff --git a/Classes/ShareKit/UI/SHKShareMenu.m b/Classes/ShareKit/UI/SHKShareMenu.m index 161175fc..a496a112 100644 --- a/Classes/ShareKit/UI/SHKShareMenu.m +++ b/Classes/ShareKit/UI/SHKShareMenu.m @@ -170,7 +170,7 @@ - (NSMutableArray *)section:(NSString *)section [sectionData addObject:[NSDictionary dictionaryWithObjectsAndKeys:sharerClassName,@"className",[class sharerTitle],@"name",nil]]; } - if (sectionData.count) + if (sectionData.count && SHKShareMenuAlphabeticalOrder) [sectionData sortUsingDescriptors:[NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)] autorelease]]]; return sectionData; From 0af9e32b54a618f9e52ade68954692e215cdff5f Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 17 Aug 2010 20:53:03 +0800 Subject: [PATCH 23/50] Fix crash due to asking for session for AutoShare when the Sharer is set to NO for AutoShare --- .../ShareKit/Core/Base Sharer Classes/SHKSharer.m | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m index 2decedd6..7d9770ea 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m @@ -523,9 +523,12 @@ - (void)shareFormSave:(SHKFormController *)form } // Update shouldAutoShare - NSDictionary *advancedOptions = [form formValuesForSection:1]; - if ([advancedOptions objectForKey:@"autoShare"] != nil) - [self setShouldAutoShare:[[advancedOptions objectForKey:@"autoShare"] isEqualToString:SHKFormFieldSwitchOn]]; + if ([[self class] canAutoShare]) + { + NSDictionary *advancedOptions = [form formValuesForSection:1]; + if ([advancedOptions objectForKey:@"autoShare"] != nil) + [self setShouldAutoShare:[[advancedOptions objectForKey:@"autoShare"] isEqualToString:SHKFormFieldSwitchOn]]; + } // Send the share [self tryToSend]; @@ -550,6 +553,10 @@ - (BOOL)validateItem case SHKShareTypeText: return (item.text != nil); break; + + case SHKShareTypeFile: + return (item.data != nil); + break; } return NO; From f83bbca13e483b50d4ffab8de57bd293910cc145 Mon Sep 17 00:00:00 2001 From: Victor Date: Tue, 17 Aug 2010 20:54:02 +0800 Subject: [PATCH 24/50] Username/password texfield should not have autocorrection and autocapitalization --- Classes/ShareKit/UI/SHKFormFieldCell.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Classes/ShareKit/UI/SHKFormFieldCell.m b/Classes/ShareKit/UI/SHKFormFieldCell.m index f91b8e06..f8edc66b 100644 --- a/Classes/ShareKit/UI/SHKFormFieldCell.m +++ b/Classes/ShareKit/UI/SHKFormFieldCell.m @@ -74,6 +74,8 @@ - (void)layoutSubviews if (settings.type == SHKFormFieldTypeText || settings.type == SHKFormFieldTypePassword) { self.textField.secureTextEntry = settings.type == SHKFormFieldTypePassword; + self.textField.autocorrectionType = UITextAutocorrectionTypeNo; + self.textField.autocapitalizationType = UITextAutocapitalizationTypeNone; textField.frame = CGRectMake(labelWidth + SHK_FORM_CELL_PAD_LEFT, 2 + round(self.contentView.bounds.size.height/2 - textField.bounds.size.height/2), From 07bab21a827e9f2f729bf125eda5cf877f8a441f Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 18 Aug 2010 23:47:42 +0800 Subject: [PATCH 25/50] fix: UIImageJPEGRepresentation specification takes in compression ratio from 0.0 to 1.0 --- Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m index 9a8402f4..aa751e9d 100644 --- a/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m +++ b/Classes/ShareKit/Sharers/Services/Tumblr/SHKTumblr.m @@ -219,7 +219,7 @@ - (BOOL)send{ } else if([item shareType] == SHKShareTypeImage){ - NSData *imageData = UIImageJPEGRepresentation([item image], 90); + NSData *imageData = UIImageJPEGRepresentation([item image], 0.9); NSMutableURLRequest *aRequest = [[[NSMutableURLRequest alloc] init] autorelease]; [aRequest setURL:[NSURL URLWithString:kTumblrWriteURL]]; [aRequest setHTTPMethod:@"POST"]; From 0f878ea0c067aab47fc2e6a5ec64ed4eb0bb03b2 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 16 Aug 2010 12:38:57 +0200 Subject: [PATCH 26/50] add localization for example document --- Classes/Example/RootViewController.m | 8 ++++---- Classes/Example/ShareKitAppDelegate.m | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Classes/Example/RootViewController.m b/Classes/Example/RootViewController.m index 60b2e4a9..6fe12156 100644 --- a/Classes/Example/RootViewController.m +++ b/Classes/Example/RootViewController.m @@ -45,19 +45,19 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N switch (indexPath.row) { case 0: - cell.textLabel.text = @"Sharing a Link"; + cell.textLabel.text = SHKLocalizedString(@"Sharing a Link"); break; case 1: - cell.textLabel.text = @"Sharing an Image"; + cell.textLabel.text = SHKLocalizedString(@"Sharing an Image"); break; case 2: - cell.textLabel.text = @"Sharing Text"; + cell.textLabel.text = SHKLocalizedString(@"Sharing Text"); break; case 3: - cell.textLabel.text = @"Sharing a File"; + cell.textLabel.text = SHKLocalizedString(@"Sharing a File"); break; //case 4: diff --git a/Classes/Example/ShareKitAppDelegate.m b/Classes/Example/ShareKitAppDelegate.m index c9c6a0bc..e905ec41 100644 --- a/Classes/Example/ShareKitAppDelegate.m +++ b/Classes/Example/ShareKitAppDelegate.m @@ -27,7 +27,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [window addSubview:[navigationController view]]; [window makeKeyAndVisible]; - navigationController.topViewController.title = @"Examples"; + navigationController.topViewController.title = SHKLocalizedString(@"Examples"); [navigationController setToolbarHidden:NO]; [self performSelector:@selector(testOffline) withObject:nil afterDelay:0.5]; From e505e4df9dc97ba03e83a9e4a717960c8895bc03 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 16 Aug 2010 12:45:24 +0200 Subject: [PATCH 27/50] fixed localization in ShareKit example code --- .../de.lproj/Localizable.strings | Bin 7834 -> 0 bytes .../en.lproj/Localizable.strings | Bin 7430 -> 0 bytes ShareKit.bundle/de.lproj/Localizable.strings | Bin 9286 -> 8220 bytes ShareKit.bundle/en.lproj/Localizable.strings | Bin 8744 -> 7834 bytes ShareKit.xcodeproj/project.pbxproj | 11 +++++------ 5 files changed, 5 insertions(+), 6 deletions(-) delete mode 100644 Classes/ShareKit/ShareKit.bundle/de.lproj/Localizable.strings delete mode 100644 Classes/ShareKit/ShareKit.bundle/en.lproj/Localizable.strings diff --git a/Classes/ShareKit/ShareKit.bundle/de.lproj/Localizable.strings b/Classes/ShareKit/ShareKit.bundle/de.lproj/Localizable.strings deleted file mode 100644 index 97829067856816cd80ba34acad1ed4b16f557608..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7834 zcmchc%Whmn6h&*yS6m`7Ll#Jkf{<{MPGmt6%XUD?to?4K-8OC~A^A|IO!x*y5wKTn zA6M1AxBZABWI5@sI(44=JgWTfKljokoup}+rFpuSy7Ys7+qLi07g~9dmgyj!r-f)w z^r_GecYI<~luP}*OQ$-wU!7=oF0|tlk3~7x&#BII>8tc(b;f%~k{mle^H9`_bRqp0 z=}n{8ulhFA4qAtV?Q|@y&KtU&OgGPK=J_;he2~`iPqFl=XpVI{)c!>W z@s<3C;(L}ohUdzepJeq(jxDF~QpniJezb=IAzri1)_O;0juh|0v8;rrh%GoOG~3xf z=zoy@%o>N(XQIXanxofd>BA^x;acc|+x3yJqZ0_J5&J~)(1k21c%2BTuM zMtJol6Pu-UtNRuo zis`U_LpntD2=0^2h0Hk84^at58#IKPq` zXre!K^2DifW1cf-q0bjuTQ)Y5Q6MpNTC0#@yF2ADc}?Af4!?k2c!Ae*?Sr210qgJb zI+`uyH|vCdABy@w8DUOSQ6Aw2q7fF2Q-?mR~=`?twI?zRsj*L!`<6Ea+>%kg& zyN)cRp=&eiRI6H&Q5CWrvA(99yN!lm*fQz$eU18(r;5&@INQpCLToD4Zb$y4663Wx zbJw%w?e16w#Pf7_<`udaTH!-iQ|c++Azw+?vqoiK-cVB`;&u94=cxz8jw$eWapwQI zzJ~^{v>(+Ny0FfEM3cbpDjyz*Clg2AUxqr_;~*Nl97p@_rMyG`I?=x%2Mjyc$ZB$g ziL{L!ntJYpQ*_1feC@5si<9&*^RPD}OS&|ssdvE%nSrb~(t%1tj?rP!Yd3!ar=~GF zYOj~PpHvpT&-S8qYuEi7(AU=r`pB3K@n@o>50W>;#8bch)G0#kyk7h0aXz`sILEef zXW(?y*Zy2zaIte)LGjFao(Gs}9LG{;*rU7SJABG__u@5u+swE?M@~}R$QH5{JD>-d z&XHR8N10ET>bdEztgUrb^vu+++Fg1e$*ww4>6b!+Cl@pdY{89uIZJcia?wmxV7 zy1y7zU8<*`I2C$RKON(~=4~AD!Ehej%vSA6D{dY2++B3umYrx)rov9Q0IEX&^rz^) zE!kl0efnA)$rb#=J&9je5PT0dV@hzZJJ3EAsl;PXd_XZd&%{s8EftBI5nM-WT!*PT zHg_N2-_Xl*!iMq-sd&50ef1=Q{JWtQ?n8Xu##89=xw86ZpG2N=gJxRttp2&|9Y-}; zM`a?*sHEe#9*bdZ&-Lhzyd2{)hH+j8YK?rp&QLfJ7m)5d0Da3fc_EzAZOCj-R{efZ zDoNW7s6qWVAo!X~zbC}>J?>ZVTdKaNE^b9LaU;6?@B8f&*};v;6XcdoO>@rG(_iuL zB%h>~#~mxG$7()fJ|3%q*IP713URr}{m}J+36MI`uj}nBJ&v389L=` zvhjvP*4*BP$mAi9PqX8B?n&edsA0;Os_xM{XO&+!278_6eclB<@ds|#g#vn=JL`VB zFOKbOK^ugqcJQhj@- zsPX++pF9oHyIFG-T@&bF@L{%V^CVshc}*+%9ljdVGkjBSB}NN=0xQHl>flG&0as>J z_8jqYw`0P)U5stb@a|Q6#kci%^DDLBMee01S+|Iwr#yVc>#M6;i;VEWI6@-UtEyMO z=e)}ia!f;K`=jVtYSvDp*WK!=-+PAdPezjeYCvajhai7kN!RqLy$yjC;~P!u%EUWv zd6^1N)h|?iY5g98w0d&%Oc3o{hP4P{iyW7&?idouXf( zN<{d}3vXtA$KedKIQ_#p;`d8(u;u$P(@^=ws`6OpFUZ==Kwq>2{3VopV~sKn#_ z2@9a|O_*CD73BZIXX`WW9;>YLRO6UYjnSDYkiQ9i9&7u!Se=!v)}f7S$K7)@xN*MZ zqouDY+vP7z2vaXRUuU=R`<7B)inXo5*B{B^by1V8@ns;1I6J+tez zSvv$-iPy6|-PPSS-81v=KPRCVW?>X2VH!?C6@JHGKK5I9fRT4$9mZi5=8&D?DaqE~ zXht8BYkaFe+T8YZxwQ1+oQjV6rC7%4_9$r7a>m-G-CH_+>I?Z-@N1Yg!p+Ys6`Vpf?^vd3FY zW0Lw4GW6DK@?*JF(qu9xK@vWX#%4cON_k!;IgU!Q2j(&k$zmFj#2MmF_A#a&eK~HH zxr%OLwsLO=@IHT&X3T-2f|W&WU2sE=Jw$E=Z&yyzk4fqkBrc=Iq|c9eDap~# zmq1X~0L^Na@mh$!LWQlPOLp`3nyt!3&&4f9yu{EZLoKY@WHh6~l{Jr^)1!CcZFp7F zw~wsQ<&vf^_rtHfgrHegTHga>1%DT)T+_(+Ii5EdTW4O7c~?=^{7Bh6M2E%f9Pt|8 z*4_%=6?n)Iq8kC95VGU&H~;6Is_T43p`1m3>6SJN&z)At(l z*!9^17_kYSRV!G#rpPF{oHDkryrPq%t5Dt8SvJwe1#Hr5T9~5hRp@_2@HjjPkMMnQ z+w~buc}HYgq3m+RMP{8kbU(_Tylald82c@DXJ5y6OG@Kkh{iR%oZ&y?R7F4Ky|_KY zNS-gnkUKUq!0Nn3+DGSZv>TIp$cQ2R8vP)e9Pd+?t9|87KkGX8SnM(Eu8gzx!Q>Ea zE%Dp$V7>3%W-BYh+xoSR5w^X6a+9hHqt8ysJTWKytsZxZUwzGqF3;8q=k$R5YmHxJf)@vZ~{S5~5RGPYu`AN1+!Z)lCyK&X+%p&e$ za*i}d{w^%aL-zHAy!ke)O{OhQ_scxhG2J9G`s7y+nJ8~ucgc12u+0A9YiyfFBILcP udBR;endbLEbBgnP7S$r{v^Wf>L0%udwvwPl9R? yHfQwaGOkBVo9+0Lm?qDX5}Uk1PGEAD(6r50gr6~Oo+ZA9hmmWdqxeR#EJgrIa3a0{ delta 578 zcmbQ^aLj}0|G&u(_)0VKuZ#VUIMu;2griBFbBvl2C`u;&E$}t{DR%VI1y-R8qi5Z=>l2A zz%|*NLth!yQ3XKL^S}X>2y}c3&=w$nawdl(QR)hX^d}ebO#``p@)AK2b~HCmo+Bs& z7t<8b-K@iZ2<%lwcVM9BGo%B(nF{k5FdU1Z0RW5`pcBB})P;GIpbl_Yz7*WZ0|4mC Bg5&@I diff --git a/ShareKit.bundle/en.lproj/Localizable.strings b/ShareKit.bundle/en.lproj/Localizable.strings index ec9b85272d416f8b4a56b677cb3fdb9a03d3bb87..ebc4261698c2ce0d9f33e88be430d224ea1d935c 100644 GIT binary patch delta 115 zcmZ4CGRv0f|G&-C7^ksrE@H1?oU9`tFj+uUiCLAwVe)={TTUR&pu}L!z%{v1Ko=@1 zJ=sP;3e0}Y5x)5j=Q^g%F1#vClRG5DCVvo^H2IKF*XCV9ZcLMz#2hyN64m2jSZG3Wzf2~a#2=)xR?p-65- z)2m91UhB=@xipz3i?AE11_7;31bQ6g?i?Ts;`SUMzZl3y^8=BpIe|XD#V)0c>XZVY znR!5O Date: Tue, 24 Aug 2010 23:12:04 +0800 Subject: [PATCH 28/50] SHKTwitter : added img.ly image sharing for --- .../Sharers/Services/Twitter/SHKTwitter.h | 3 + .../Sharers/Services/Twitter/SHKTwitter.m | 139 ++++++++++++++++-- 2 files changed, 133 insertions(+), 9 deletions(-) diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h index 57569157..cbb02783 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.h @@ -53,6 +53,9 @@ - (void)sendStatus; - (void)sendStatusTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data; - (void)sendStatusTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error; +- (void)sendImage; +- (void)sendImageTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data; +- (void)sendImageTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error; - (void)followMe; diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index 5a128e8d..5a7430ec 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -78,10 +78,10 @@ + (BOOL)canShareText } // TODO use img.ly to support this -//+ (BOOL)canShareImage -//{ -// return YES; -//} ++ (BOOL)canShareImage +{ + return YES; +} #pragma mark - @@ -293,12 +293,11 @@ - (BOOL)send else { - //if (item.shareType == SHKShareTypeImage) - // [self sendImage]; - - //else + if (item.shareType == SHKShareTypeImage) { + [self sendImage]; + } else { [self sendStatus]; - + } // Notify delegate [self sendDidStart]; @@ -351,6 +350,128 @@ - (void)sendStatusTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)er [self sendDidFailWithError:error]; } +- (void)sendImage { + + NSURL *serviceURL = nil; + if([item customValueForKey:@"profile_update"]){ + serviceURL = [NSURL URLWithString:@"http://api.twitter.com/1/account/update_profile_image.json"]; + } else { + serviceURL = [NSURL URLWithString:@"https://api.twitter.com/1/account/verify_credentials.json"]; + } + + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:serviceURL + consumer:consumer + token:accessToken + realm:@"http://api.twitter.com/" + signatureProvider:signatureProvider]; + [oRequest setHTTPMethod:@"GET"]; + + if([item customValueForKey:@"profile_update"]){ + [oRequest prepare]; + } else { + [oRequest prepare]; + + NSDictionary * headerDict = [oRequest allHTTPHeaderFields]; + NSString * oauthHeader = [NSString stringWithString:[headerDict valueForKey:@"Authorization"]]; + + [oRequest release]; + oRequest = nil; + + serviceURL = [NSURL URLWithString:@"http://img.ly/api/2/upload.xml"]; + oRequest = [[OAMutableURLRequest alloc] initWithURL:serviceURL + consumer:consumer + token:accessToken + realm:@"http://api.twitter.com/" + signatureProvider:signatureProvider]; + [oRequest setHTTPMethod:@"POST"]; + [oRequest setValue:@"https://api.twitter.com/1/account/verify_credentials.json" forHTTPHeaderField:@"X-Auth-Service-Provider"]; + [oRequest setValue:oauthHeader forHTTPHeaderField:@"X-Verify-Credentials-Authorization"]; + } + + CGFloat compression = 0.9f; + NSData *imageData = UIImageJPEGRepresentation([item image], compression); + + while ([imageData length] > 700000 && compression > 0.1) { + // NSLog(@"Image size too big, compression more: current data size: %d bytes",[imageData length]); + compression -= 0.1; + imageData = UIImageJPEGRepresentation([item image], compression); + + } + + NSString *boundary = @"0xKhTmLbOuNdArY"; + NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary]; + [oRequest setValue:contentType forHTTPHeaderField:@"Content-Type"]; + + NSMutableData *body = [NSMutableData data]; + NSString *dispKey = @""; + if([item customValueForKey:@"profile_update"]){ + dispKey = @"Content-Disposition: form-data; name=\"image\"; filename=\"upload.jpg\"\r\n"; + } else { + dispKey = @"Content-Disposition: form-data; name=\"media\"; filename=\"upload.jpg\"\r\n"; + } + + + [body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[dispKey dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"Content-Type: image/jpg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:imageData]; + [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + + if([item customValueForKey:@"profile_update"]){ + // no ops + } else { + [body appendData:[[NSString stringWithFormat:@"--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name=\"message\"\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[[item customValueForKey:@"status"] dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + } + + [body appendData:[[NSString stringWithFormat:@"--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + + // setting the body of the post to the reqeust + [oRequest setHTTPBody:body]; + + // Notify delegate + [self sendDidStart]; + + // Start the request + OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest + delegate:self + didFinishSelector:@selector(sendImageTicket:didFinishWithData:) + didFailSelector:@selector(sendImageTicket:didFailWithError:)]; + + [fetcher start]; + + + [oRequest release]; +} + +- (void)sendImageTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data { + // TODO better error handling here + // NSLog([[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); + + if (ticket.didSucceed) { + [self sendDidFinish]; + // Finished uploading Image, now need to posh the message and url in twitter + NSString *dataString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + NSRange startingRange = [dataString rangeOfString:@"" options:NSCaseInsensitiveSearch]; + //NSLog(@"found start string at %d, len %d",startingRange.location,startingRange.length); + NSRange endingRange = [dataString rangeOfString:@"" options:NSCaseInsensitiveSearch]; + //NSLog(@"found end string at %d, len %d",endingRange.location,endingRange.length); + NSString *urlString = [dataString substringWithRange:NSMakeRange(startingRange.location + startingRange.length, endingRange.location - (startingRange.location + startingRange.length))]; + //NSLog(@"extracted string: %@",urlString); + + [item setCustomValue:[NSString stringWithFormat:@"%@ %@",[item customValueForKey:@"status"],urlString] forKey:@"status"]; + [self sendStatus]; + } else { + [self sendDidFailWithError:nil]; + } +} + +- (void)sendImageTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error { + [self sendDidFailWithError:error]; +} + - (void)followMe { From 779093f9eeeee7448b269a86c901e9cf95574fee Mon Sep 17 00:00:00 2001 From: adamawolf Date: Fri, 6 Aug 2010 14:32:03 +0800 Subject: [PATCH 29/50] fixing crash caused by malformed error message formatting in case of oauth authentication failure --- Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m index 5b39f324..0badf306 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m @@ -121,7 +121,7 @@ - (void)tokenRequestTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData * else // TODO - better error handling here - [self tokenRequestTicket:ticket didFailWithError:[SHK error:SHKLocalizedString(@"There was a problem requesting authorization from %@"), [self sharerTitle]]]; + [self tokenRequestTicket:ticket didFailWithError:[SHK error:SHKLocalizedString(@"There was a problem requesting authorization from %@", [self sharerTitle])]]; } - (void)tokenRequestTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error From b9fb96a7345238c5b3e4b346bcb873ab691e04e5 Mon Sep 17 00:00:00 2001 From: innopage Date: Wed, 25 Aug 2010 00:02:50 +0800 Subject: [PATCH 30/50] Fix OAMutableURLRequest bugs with parameters --- .../Core/Helpers/OAuth/OAMutableURLRequest.h | 1 + .../Core/Helpers/OAuth/OAMutableURLRequest.m | 25 +++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.h b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.h index fdf0a1a8..03c6cfac 100755 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.h +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.h @@ -43,6 +43,7 @@ NSString *nonce; NSString *timestamp; NSMutableDictionary *extraOAuthParameters; + BOOL didPrepare; } @property(readonly) NSString *signature; @property(readonly) NSString *nonce; diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m index 5327b895..8164b7b9 100755 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m @@ -70,6 +70,8 @@ - (id)initWithURL:(NSURL *)aUrl [self _generateTimestamp]; [self _generateNonce]; + + didPrepare = NO; } return self; } @@ -109,6 +111,8 @@ - (id)initWithURL:(NSURL *)aUrl timestamp = [aTimestamp retain]; nonce = [aNonce retain]; + + didPrepare = NO; } return self; } @@ -141,6 +145,10 @@ - (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)para - (void)prepare { + if (didPrepare) { + return; + } + didPrepare = YES; // sign // Secrets must be urlencoded before concatenated with '&' // TODO: if later RSA-SHA1 support is added then a little code redesign is needed @@ -175,7 +183,7 @@ - (void)prepare timestamp, nonce, extraParameters]; - + [self setValue:oauthHeader forHTTPHeaderField:@"Authorization"]; } @@ -199,7 +207,7 @@ - (NSString *)_signatureBaseString { // OAuth Spec, Section 9.1.1 "Normalize Request Parameters" // build a sorted array of both request parameters and OAuth header parameters - NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:(6 + [[self parameters] count])]; // 6 being the number of OAuth params in the Signature Base String + NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:(6)]; // 6 being the number of OAuth params in the Signature Base String [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_consumer_key" value:consumer.key] URLEncodedNameValuePair]]; [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_signature_method" value:[signatureProvider name]] URLEncodedNameValuePair]]; @@ -211,9 +219,16 @@ - (NSString *)_signatureBaseString [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_token" value:token.key] URLEncodedNameValuePair]]; } - for (OARequestParameter *param in [self parameters]) { - [parameterPairs addObject:[param URLEncodedNameValuePair]]; - } + + for(NSString *parameterName in [[extraOAuthParameters allKeys] sortedArrayUsingSelector:@selector(compare:)]) { + [parameterPairs addObject:[[OARequestParameter requestParameterWithName:[parameterName URLEncodedString] value: [[extraOAuthParameters objectForKey:parameterName] URLEncodedString]] URLEncodedNameValuePair]]; + } + + if (![[self valueForHTTPHeaderField:@"Content-Type"] hasPrefix:@"multipart/form-data"]) { + for (OARequestParameter *param in [self parameters]) { + [parameterPairs addObject:[param URLEncodedNameValuePair]]; + } + } NSArray *sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)]; NSString *normalizedRequestParameters = [sortedPairs componentsJoinedByString:@"&"]; From dd09d50b5d46fd1480afead461d16d25b58f6f7b Mon Sep 17 00:00:00 2001 From: innopage Date: Wed, 25 Aug 2010 10:55:11 +0800 Subject: [PATCH 31/50] Fix UIImageJPEGRepresentation only takes in compression ratio from 0.0 to 1.0 --- Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 1a44bbf7..11afa0b8 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -182,7 +182,7 @@ - (void)sendImage [[FBRequest requestWithDelegate:self] call:@"facebook.photos.upload" params:[NSDictionary dictionaryWithObjectsAndKeys:item.title, @"caption", nil] - dataParam:UIImageJPEGRepresentation(item.image,100)]; + dataParam:UIImageJPEGRepresentation(item.image,1.0)]; } - (void)dialogDidSucceed:(FBDialog*)dialog From 1e55db251285b0db5e800e1a050e6c2593afa529 Mon Sep 17 00:00:00 2001 From: adamawolf Date: Mon, 16 Aug 2010 17:29:09 +0800 Subject: [PATCH 32/50] BUGFIX: in facebook if you login->logout->log back in, the post window doesn't appear the second time --- Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index 11afa0b8..c78b762c 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -103,7 +103,7 @@ - (BOOL)isAuthorized - (void)promptAuthorization { self.pendingFacebookAction = SHKFacebookPendingLogin; - self.login = [[[FBLoginDialog alloc] init] autorelease]; + self.login = [[[FBLoginDialog alloc] initWithSession:[self session]] autorelease]; [login show]; } From 1b407d8d21dde090eeb5a380a5f09169156a1914 Mon Sep 17 00:00:00 2001 From: Bryan Bonczek Date: Tue, 3 Aug 2010 23:59:22 +0800 Subject: [PATCH 33/50] Added session proxy support for Facebook Connect. --- Classes/ShareKit/SHKConfig.h | 4 ++++ .../Sharers/Services/Facebook/SHKFacebook.m | 21 ++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 9d0e809e..8117453e 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -43,8 +43,12 @@ #define SHKDeliciousSecretKey @"" // Facebook - http://www.facebook.com/developers +// If SHKFacebookUseSessionProxy is enabled then SHKFacebookSecret is ignored and should be left blank + +#define SHKFacebookUseSessionProxy NO #define SHKFacebookKey @"" #define SHKFacebookSecret @"" +#define SHKFacebookSessionProxyURL @"" // Read It Later - http://readitlaterlist.com/api/?shk #define SHKReadItLaterKey @"" diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index c78b762c..fd7836a9 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -34,7 +34,6 @@ @implementation SHKFacebook @synthesize pendingFacebookAction; @synthesize login; - - (void)dealloc { [session.delegates removeObject:self]; @@ -72,8 +71,6 @@ + (BOOL)canShareOffline return NO; // TODO - would love to make this work } - - #pragma mark - #pragma mark Configuration : Dynamic Enable @@ -82,8 +79,6 @@ - (BOOL)shouldAutoShare return YES; // FBConnect presents its own dialog } - - #pragma mark - #pragma mark Authentication @@ -91,9 +86,19 @@ - (BOOL)isAuthorized { if (session == nil) { - self.session = [FBSession sessionForApplication:SHKFacebookKey - secret:SHKFacebookSecret - delegate:self]; + + if(!SHKFacebookUseSessionProxy){ + self.session = [FBSession sessionForApplication:SHKFacebookKey + secret:SHKFacebookSecret + delegate:self]; + + }else { + self.session = [FBSession sessionForApplication:SHKFacebookKey + getSessionProxy:SHKFacebookSessionProxyURL + delegate:self]; + } + + return [session resume]; } From f084a1384dc597edcafc8f4da2fb461341adc160 Mon Sep 17 00:00:00 2001 From: Bryan Bonczek Date: Wed, 4 Aug 2010 00:19:50 +0800 Subject: [PATCH 34/50] Modified Facebook logout code to work with session proxying. --- .../Sharers/Services/Facebook/SHKFacebook.m | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m index fd7836a9..44f0b85a 100644 --- a/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m +++ b/Classes/ShareKit/Sharers/Services/Facebook/SHKFacebook.m @@ -119,9 +119,19 @@ - (void)authFinished:(SHKRequest *)request + (void)logout { - FBSession *fbSession = [FBSession sessionForApplication:SHKFacebookKey - secret:SHKFacebookSecret - delegate:[[[self alloc] init] autorelease]]; + FBSession *fbSession; + + if(!SHKFacebookUseSessionProxy){ + fbSession = [FBSession sessionForApplication:SHKFacebookKey + secret:SHKFacebookSecret + delegate:self]; + + }else { + fbSession = [FBSession sessionForApplication:SHKFacebookKey + getSessionProxy:SHKFacebookSessionProxyURL + delegate:self]; + } + [fbSession logout]; } From 4ffde13e3263c5f040b29ab8425302c43cc0b290 Mon Sep 17 00:00:00 2001 From: innopage Date: Wed, 25 Aug 2010 00:02:28 +0800 Subject: [PATCH 35/50] Better Error handling for image upload --- .../ShareKit/Sharers/Services/Twitter/SHKTwitter.m | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index 5a7430ec..8c5d2307 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -458,11 +458,15 @@ - (void)sendImageTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)da //NSLog(@"found start string at %d, len %d",startingRange.location,startingRange.length); NSRange endingRange = [dataString rangeOfString:@"" options:NSCaseInsensitiveSearch]; //NSLog(@"found end string at %d, len %d",endingRange.location,endingRange.length); - NSString *urlString = [dataString substringWithRange:NSMakeRange(startingRange.location + startingRange.length, endingRange.location - (startingRange.location + startingRange.length))]; - //NSLog(@"extracted string: %@",urlString); - [item setCustomValue:[NSString stringWithFormat:@"%@ %@",[item customValueForKey:@"status"],urlString] forKey:@"status"]; - [self sendStatus]; + if (startingRange != NSNotFound && endingRange != NSNotFound) { + NSString *urlString = [dataString substringWithRange:NSMakeRange(startingRange.location + startingRange.length, endingRange.location - (startingRange.location + startingRange.length))]; + //NSLog(@"extracted string: %@",urlString); + [item setCustomValue:[NSString stringWithFormat:@"%@ %@",[item customValueForKey:@"status"],urlString] forKey:@"status"]; + [self sendStatus]; + } + + } else { [self sendDidFailWithError:nil]; } From 83d0c56e3eb87507f2df97df4991f2811dec564d Mon Sep 17 00:00:00 2001 From: innopage Date: Wed, 25 Aug 2010 10:49:38 +0800 Subject: [PATCH 36/50] Fix bug on image upload url checking --- Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index 8c5d2307..b0ec38bc 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -459,7 +459,7 @@ - (void)sendImageTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)da NSRange endingRange = [dataString rangeOfString:@"" options:NSCaseInsensitiveSearch]; //NSLog(@"found end string at %d, len %d",endingRange.location,endingRange.length); - if (startingRange != NSNotFound && endingRange != NSNotFound) { + if (startingRange.location != NSNotFound && endingRange.location != NSNotFound) { NSString *urlString = [dataString substringWithRange:NSMakeRange(startingRange.location + startingRange.length, endingRange.location - (startingRange.location + startingRange.length))]; //NSLog(@"extracted string: %@",urlString); [item setCustomValue:[NSString stringWithFormat:@"%@ %@",[item customValueForKey:@"status"],urlString] forKey:@"status"]; From cf3bdfb6f36088fffd6603d74d92a4d0ee65be21 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Thu, 26 Aug 2010 14:32:03 -0700 Subject: [PATCH 37/50] =?UTF-8?q?-=20New:=20Option=20to=20disable=20'share?= =?UTF-8?q?d=20with=20=E2=80=A6'=20email=20signature=20-=20New:=20Added=20?= =?UTF-8?q?'logout'=20button=20example=20to=20project?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Improved: Moved translations into file structure that is easier to view in github - Fixed: Translations not being applied - Fixed: C++ compile error because of 'new' in SHKSwizzle - Fixed: Twitter message dialog appearing blank - Fixed: Twitter failed to login with special characters (%&,etc) in password - Fixed: OAuth logout now flushes cookies from domain too - Fixed: Twitter dialog does not display 'ALREADY_A_BITLY_LINK' from bit.ly response - Fixed: SHKMail now listens to SHKModalTransitionStyle - Fixed: SHKMail signature not localized - Fixed: Problems in devices without email configured - Fixed: Issue where SHKActionSheet could respond to the incorrect choice - Fixed: Removed auto-correction form login form fields --- Classes/Example/ExampleShareFile.m | 1 + Classes/Example/ExampleShareLink.m | 3 +- Classes/Example/RootViewController.m | 30 ++++++ .../Core/Base Sharer Classes/SHKOAuthSharer.m | 14 +++ .../Core/Base Sharer Classes/SHKSharer.h | 1 + .../Core/Base Sharer Classes/SHKSharer.m | 20 +++- .../Core/Helpers/OAuth/OAMutableURLRequest.m | 66 ++++++------- Classes/ShareKit/Core/SHK.h | 3 +- Classes/ShareKit/Core/SHK.m | 26 +++-- .../Localization/de.lproj/Localizable.strings | 96 +++++++++++++++++++ .../Localization/en.lproj/Localizable.strings | 91 ++++++++++++++++++ Classes/ShareKit/SHKConfig.h | 13 ++- .../ShareKit/Sharers/Actions/Copy/SHKCopy.m | 4 + .../ShareKit/Sharers/Actions/Email/SHKMail.m | 24 ++++- .../Actions/Open in Safari/SHKSafari.m | 4 + .../Sharers/Services/Twitter/SHKTwitter.m | 65 +++++++++++-- .../Sharers/Services/Twitter/SHKTwitterForm.m | 2 +- Classes/ShareKit/UI/SHKActionSheet.h | 4 +- Classes/ShareKit/UI/SHKActionSheet.m | 12 ++- Classes/ShareKit/UI/SHKFormFieldCell.m | 3 +- ShareKit.xcodeproj/project.pbxproj | 34 +++++-- 21 files changed, 439 insertions(+), 77 deletions(-) create mode 100644 Classes/ShareKit/Localization/de.lproj/Localizable.strings create mode 100644 Classes/ShareKit/Localization/en.lproj/Localizable.strings diff --git a/Classes/Example/ExampleShareFile.m b/Classes/Example/ExampleShareFile.m index 3a76c403..142d00cb 100644 --- a/Classes/Example/ExampleShareFile.m +++ b/Classes/Example/ExampleShareFile.m @@ -62,6 +62,7 @@ - (void)loadView [webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"example.pdf"]]]]; self.view = webView; + [webView release]; } - (void)share diff --git a/Classes/Example/ExampleShareLink.m b/Classes/Example/ExampleShareLink.m index aa2ba202..308de462 100644 --- a/Classes/Example/ExampleShareLink.m +++ b/Classes/Example/ExampleShareLink.m @@ -57,7 +57,7 @@ - (void)share { SHKItem *item = [SHKItem URL:webView.request.URL title:[webView pageTitle]]; SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item]; - [actionSheet showFromToolbar:self.navigationController.toolbar]; + [actionSheet showFromToolbar:self.navigationController.toolbar]; } - (void)loadView @@ -68,6 +68,7 @@ - (void)loadView [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://apple.com"]]]; self.view = webView; + [webView release]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation diff --git a/Classes/Example/RootViewController.m b/Classes/Example/RootViewController.m index 6fe12156..0e873e2e 100644 --- a/Classes/Example/RootViewController.m +++ b/Classes/Example/RootViewController.m @@ -15,6 +15,16 @@ @implementation RootViewController +- (void)loadView +{ + [super loadView]; + + self.toolbarItems = [NSArray arrayWithObjects: + [[[UIBarButtonItem alloc] initWithTitle:SHKLocalizedString(@"Logout") style:UIBarButtonItemStyleBordered target:self action:@selector(logout)] autorelease], + nil + ]; +} + #pragma mark - #pragma mark Table view data source @@ -106,5 +116,25 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface } +#pragma mark - + +- (void)logout +{ + [[[[UIAlertView alloc] initWithTitle:SHKLocalizedString(@"Logout") + message:SHKLocalizedString(@"Are you sure you want to logout of all share services?") + delegate:self + cancelButtonTitle:SHKLocalizedString(@"Cancel") + otherButtonTitles:@"Logout",nil] autorelease] show]; + + [SHK logoutOfAll]; +} + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (buttonIndex == 0) + [SHK logoutOfAll]; +} + + @end diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m index 0badf306..e2edf057 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKOAuthSharer.m @@ -272,6 +272,20 @@ + (void)deleteStoredAccessToken + (void)logout { [self deleteStoredAccessToken]; + + // Clear cookies (for OAuth, doesn't affect XAuth) + // TODO - move the authorizeURL out of the init call (into a define) so we don't have to create an object just to get it + SHKOAuthSharer *sharer = [[self alloc] init]; + if (sharer.authorizeURL) + { + NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + NSArray *cookies = [storage cookiesForURL:sharer.authorizeURL]; + for (NSHTTPCookie *each in cookies) + { + [storage deleteCookie:each]; + } + } + [sharer release]; } - (BOOL)restoreAccessToken diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h index 02063467..e608d072 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.h @@ -145,6 +145,7 @@ typedef enum + (NSArray *)authorizationFormFields; + (NSString *)authorizationFormCaption; + (void)logout; ++ (BOOL)isServiceAuthorized; #pragma mark - #pragma mark API Implementation diff --git a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m index 7d9770ea..f7c331fa 100644 --- a/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m +++ b/Classes/ShareKit/Core/Base Sharer Classes/SHKSharer.m @@ -421,6 +421,16 @@ + (void)logout } } +// Credit: GreatWiz ++ (BOOL)isServiceAuthorized +{ + SHKSharer *controller = [[self alloc] init]; + BOOL isAuthorized = [controller isAuthorized]; + [controller release]; + + return isAuthorized; +} + @@ -672,13 +682,17 @@ - (void)viewDidDisappear:(BOOL)animated - (void)sendDidStart { if ([shareDelegate respondsToSelector:@selector(sharerStartedSending:)]) - [shareDelegate performSelector:@selector(sharerStartedSending:) withObject:self]; + [shareDelegate performSelector:@selector(sharerStartedSending:) withObject:self]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"SHKSendDidStartNotification" object:self]; } - (void)sendDidFinish { if ([shareDelegate respondsToSelector:@selector(sharerFinishedSending:)]) [shareDelegate performSelector:@selector(sharerFinishedSending:) withObject:self]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"SHKSendDidFinish" object:self]; } - (void)sendDidFailShouldRelogin @@ -697,12 +711,16 @@ - (void)sendDidFailWithError:(NSError *)error shouldRelogin:(BOOL)shouldRelogin if ([shareDelegate respondsToSelector:@selector(sharer:failedWithError:shouldRelogin:)]) [(SHKSharer *)shareDelegate sharer:self failedWithError:error shouldRelogin:shouldRelogin]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"SHKSendDidFailWithError" object:self]; } - (void)sendDidCancel { if ([shareDelegate respondsToSelector:@selector(sharerCancelledSending:)]) [shareDelegate performSelector:@selector(sharerCancelledSending:) withObject:self]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"SHKSendDidCancel" object:self]; } diff --git a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m index 8164b7b9..a91a01e7 100755 --- a/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m +++ b/Classes/ShareKit/Core/Helpers/OAuth/OAMutableURLRequest.m @@ -1,27 +1,27 @@ // -// OAMutableURLRequest.m -// OAuthConsumer +// OAMutableURLRequest.m +// OAuthConsumer // -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. // -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: // -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. #import "OAMutableURLRequest.h" @@ -43,12 +43,12 @@ - (id)initWithURL:(NSURL *)aUrl consumer:(OAConsumer *)aConsumer token:(OAToken *)aToken realm:(NSString *)aRealm -signatureProvider:(id)aProvider +signatureProvider:(id)aProvider { if (self = [super initWithURL:aUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0]) - { + { consumer = [aConsumer retain]; // empty token for Unauthorized Request Token transaction @@ -59,13 +59,13 @@ - (id)initWithURL:(NSURL *)aUrl if (aRealm == nil) realm = [[NSString alloc] initWithString:@""]; - else + else realm = [aRealm retain]; // default to HMAC-SHA1 if (aProvider == nil) signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; - else + else signatureProvider = [aProvider retain]; [self _generateTimestamp]; @@ -84,12 +84,12 @@ - (id)initWithURL:(NSURL *)aUrl realm:(NSString *)aRealm signatureProvider:(id)aProvider nonce:(NSString *)aNonce - timestamp:(NSString *)aTimestamp + timestamp:(NSString *)aTimestamp { if (self = [super initWithURL:aUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0]) - { + { consumer = [aConsumer retain]; // empty token for Unauthorized Request Token transaction @@ -100,13 +100,13 @@ - (id)initWithURL:(NSURL *)aUrl if (aRealm == nil) realm = [[NSString alloc] initWithString:@""]; - else + else realm = [aRealm retain]; // default to HMAC-SHA1 if (aProvider == nil) signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; - else + else signatureProvider = [aProvider retain]; timestamp = [aTimestamp retain]; @@ -143,7 +143,7 @@ - (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)para [extraOAuthParameters setObject:parameterValue forKey:parameterName]; } -- (void)prepare +- (void)prepare { if (didPrepare) { return; @@ -172,7 +172,7 @@ - (void)prepare [extraParameters appendFormat:@", %@=\"%@\"", [parameterName URLEncodedString], [[extraOAuthParameters objectForKey:parameterName] URLEncodedString]]; - } + } NSString *oauthHeader = [NSString stringWithFormat:@"OAuth realm=\"%@\", oauth_consumer_key=\"%@\", %@oauth_signature_method=\"%@\", oauth_signature=\"%@\", oauth_timestamp=\"%@\", oauth_nonce=\"%@\", oauth_version=\"1.0\"%@", [realm URLEncodedString], @@ -190,12 +190,12 @@ - (void)prepare #pragma mark - #pragma mark Private -- (void)_generateTimestamp +- (void)_generateTimestamp { timestamp = [[NSString stringWithFormat:@"%d", time(NULL)] retain]; } -- (void)_generateNonce +- (void)_generateNonce { CFUUIDRef theUUID = CFUUIDCreate(NULL); CFStringRef string = CFUUIDCreateString(NULL, theUUID); @@ -203,11 +203,11 @@ - (void)_generateNonce nonce = (NSString *)string; } -- (NSString *)_signatureBaseString +- (NSString *)_signatureBaseString { // OAuth Spec, Section 9.1.1 "Normalize Request Parameters" // build a sorted array of both request parameters and OAuth header parameters - NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:(6)]; // 6 being the number of OAuth params in the Signature Base String + NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:(6)]; // 6 being the number of OAuth params in the Signature Base String [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_consumer_key" value:consumer.key] URLEncodedNameValuePair]]; [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_signature_method" value:[signatureProvider name]] URLEncodedNameValuePair]]; diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index 5c90206a..f3cfbef6 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -25,7 +25,7 @@ // // -#define SHK_VERSION @"0.2.0" +#define SHK_VERSION @"0.2.1" #import #import "SHKConfig.h" @@ -70,6 +70,7 @@ #pragma mark - #pragma mark View Management ++ (void)setRootViewController:(UIViewController *)vc; - (void)showViewController:(UIViewController *)vc; - (void)hideCurrentViewControllerAnimated:(BOOL)animated; - (void)viewWasDismissed; diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m index 9eb1ea7c..2614ff81 100644 --- a/Classes/ShareKit/Core/SHK.m +++ b/Classes/ShareKit/Core/SHK.m @@ -32,7 +32,7 @@ #import "SHKOfflineSharer.h" #import "SFHFKeychainUtils.h" #import "Reachability.h" -#import +#import #import @@ -145,7 +145,13 @@ - (void)showViewController:(UIViewController *)vc // Show the nav controller else - { + { + if ([vc respondsToSelector:@selector(modalPresentationStyle)]) + vc.modalPresentationStyle = [SHK modalPresentationStyle]; + + if ([vc respondsToSelector:@selector(modalTransitionStyle)]) + vc.modalTransitionStyle = [SHK modalTransitionStyle]; + [topViewController presentModalViewController:vc animated:YES]; [(UINavigationController *)vc navigationBar].barStyle = [(UINavigationController *)vc toolbar].barStyle = [SHK barStyle]; @@ -564,28 +570,20 @@ + (BOOL)connected return result; } -void SHKSwizzle(Class c, SEL orig, SEL new) +void SHKSwizzle(Class c, SEL orig, SEL newClassName) { Method origMethod = class_getInstanceMethod(c, orig); - Method newMethod = class_getInstanceMethod(c, new); + Method newMethod = class_getInstanceMethod(c, newClassName); if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) - class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); + class_replaceMethod(c, newClassName, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); else method_exchangeImplementations(origMethod, newMethod); } NSString* SHKLocalizedString(NSString* key, ...) { - static NSBundle* bundle = nil; - if (!bundle) - { - NSString* path = [[[NSBundle mainBundle] resourcePath] - stringByAppendingPathComponent:@"ShareKit.bundle"]; - bundle = [[NSBundle bundleWithPath:path] retain]; - } - // Localize the format - NSString *localizedStringFormat = [bundle localizedStringForKey:key value:key table:nil]; + NSString *localizedStringFormat = NSLocalizedString(key, key); va_list args; va_start(args, key); diff --git a/Classes/ShareKit/Localization/de.lproj/Localizable.strings b/Classes/ShareKit/Localization/de.lproj/Localizable.strings new file mode 100644 index 00000000..bb36dab7 --- /dev/null +++ b/Classes/ShareKit/Localization/de.lproj/Localizable.strings @@ -0,0 +1,96 @@ +"Email" = "Email"; +"Username" = "Username"; +"Password" = "Passwort"; +"Follow %@" = "Folge %@"; +"Continue" = "Weiter"; +"Share" = "Teile"; +"More..." = "Mehr..."; +"Cancel" = "Abbrechen"; +"Slug" = "Slug"; +"Private" = "Privat"; +"Public" = "Öffentlich"; +"Caption" = "Kommentar"; +"Title" = "Titel"; +"Tags" = "Tags"; +"Close" = "Schließen"; +"Notes" = "Notizen"; +"Note" = "Notiz"; +"Share" = "Teilen"; +"Shared" = "Geteilt"; +"Edit" = "Editieren"; +"Actions" = "Aktionen"; +"Services" = "Dienste"; +"Send to %@" = "Zu %@ senden"; +"Copy" = "Kopieren"; +"Copied!" = "Kopiert!"; +"Saving to %@" = "Nach %@ speichern"; +"Saved!" = "Gespeichert!"; +"Offline" = "Offline"; +"Error" = "Fehler"; +"Login" = "Login"; +"Logging In..." = "Einloggen..."; +"Login Error" = "Fehler beim Login"; +"Connecting..." = "Verbinde..."; + +"Shortening URL..." = "Verkleinere URL..."; +"Shorten URL Error" = "Fehler beim Verkleinern der URL"; +"We could not shorten the URL." = "URL konnte nicht verkleinert werden."; + +"Create a free account at %@" = "Registrieren Sie einen kostenlosen Account bei %@"; +"Create an account at %@" = "Erstelle einen Account auf %@"; + +"Send to Twitter" = "An Twitter senden"; + +"Message is too long" = "Nachricht zu lang"; +"Twitter posts can only be 140 characters in length." = "Twitter Nachrichten können maximal 140 Zeichen lang sein."; +"Message is empty" = "Nachricht ist leer"; +"You must enter a message in order to post." = "Sie müssen eine Nachricht eingeben um diese absenden zu können"; + +"Enter your message:" = "Nachricht eingeben:"; + +"Invalid email or password." = "Falsche Email oder Passwort."; +"The service encountered an error. Please try again later." = "Der Dienst konnte nicht abgeschlossen werden. Bitte versuchen Sie es später erneut."; +"There was a sending your post to Tumblr." = "Beim Posten auf Tumblr trat ein Fehler auf."; + +"There was an error saving to Pinboard" = "Beim Speichern zu Pinboard trat ein Fehler auf."; + +"Sorry, Instapaper did not accept your credentials. Please try again." = "Instapaper akzeptierte Ihren Login nicht. Bitte versuchen Sie es erneut."; +"Sorry, Instapaper encountered an error. Please try again." = "Instapaper schlug fehl. Bitte versuchen Sie es erneut."; +"There was a problem saving to Instapaper." = "Beim Speichern auf Instapaper trat ein Problem auf."; + +"Incorrect username and password" = "Falscher Username und Passwort"; +"There was an error logging into Google Reader" = "Beim Einloggen zu Google Reader trat ein Fehler auf"; +"There was a problem authenticating your account." = "Beim Authentifizieren Ihres Accounts trat ein Fehler auf."; +"There was a problem saving your note." = "Beim Speichern Ihrer Notiz trat ein Problem auf."; + +"There was a problem saving to Delicious." = "Beim Speichern auf Delicious trat ein Problem auf."; + +"Open in Safari" = "In Safari öffnen"; +"Attached: %@" = "Angehängt: %@"; + +"You must be online to login to %@" = "Sie müssen online sein um sich bei %@ einzuloggen."; + +"Auto Share" = "Auto Share"; +"Enable auto share to skip this step in the future." = "Aktivieren Sie Auto Share um diesen Schritt zu überspringen."; + +"You must be online in order to share with %@" = "Um mit %@ zu teilen müssen Sie online sein."; +"There was an error while sharing" = "Beim Teilen trat ein Fehler auf."; + +"Could not authenticate you. Please relogin." = "Konnte Sie nicht authentifizieren. Bitte neu einloggen."; +"There was a problem requesting authorization from %@" = "Beim Abfragen der Authorisation für %@ trat ein Fehler auf."; +"Request Error" = "Anfragefehler"; +"There was an error while sharing" = "Beim Teilen trat ein Fehler auf."; + +"Authorize Error" = "Authorisierungsfehler"; +"There was an error while authorizing" = "Beim Authorisieren trat ein Fehler auf."; + +"Authenticating..." = "Authentifizieren..."; +"There was a problem requesting access from %@" = "Beim Nachfragen zum Zugang zu %@ trat ein Fehler auf."; + +"Access Error" = "Zugriffsfehler"; + +"Sharing a Link" = "Teile Link"; +"Sharing an Image" = "Teile Bild"; +"Sharing Text" = "Teile Text"; +"Sharing a File" = "Teile Datei"; +"Logout of All Services" = "Aus allen Services ausloggen"; \ No newline at end of file diff --git a/Classes/ShareKit/Localization/en.lproj/Localizable.strings b/Classes/ShareKit/Localization/en.lproj/Localizable.strings new file mode 100644 index 00000000..cf945769 --- /dev/null +++ b/Classes/ShareKit/Localization/en.lproj/Localizable.strings @@ -0,0 +1,91 @@ +"Email" = "Email"; +"Username" = "Username"; +"Password" = "Password"; +"Follow %@" = "Follow %@"; +"Continue" = "Continue"; +"Share" = "Share"; +"More..." = "More..."; +"Cancel" = "Cancel"; +"Slug" = "Slug"; +"Private" = "Private"; +"Public" = "Public"; +"Caption" = "Caption"; +"Title" = "Title"; +"Tags" = "Tags"; +"Close" = "Close"; +"Notes" = "Notes"; +"Note" = "Note"; +"Share" = "Share"; +"Shared" = "Shared"; +"Edit" = "Edit"; +"Actions" = "Actions"; +"Services" = "Services"; +"Send to %@" = "Send to %@"; +"Copy" = "Copy"; +"Copied!" = "Copied!"; +"Saving to %@" = "Saving to %@"; +"Saved!" = "Saved!"; +"Offline" = "Offline"; +"Error" = "Error"; +"Login" = "Login"; +"Logging In..." = "Logging In..."; +"Login Error" = "Login Error"; +"Connecting..." = "Connecting..."; + +"Shortening URL..." = "Shortening URL..."; +"Shorten URL Error" = "Shorten URL Error"; +"We could not shorten the URL." = "We could not shorten the URL."; + +"Create a free account at %@" = "Create a free account at %@"; +"Create an account at %@" = "Create an account at %@"; + +"Send to Twitter" = "Send to Twitter"; + +"Message is too long" = "Message is too long"; +"Twitter posts can only be 140 characters in length." = "Twitter posts can only be 140 characters in length."; +"Message is empty" = "Message is empty"; +"You must enter a message in order to post." = "You must enter a message in order to post."; + +"Enter your message:" = "Enter your message:"; + +"Invalid email or password." = "Invalid email or password."; +"The service encountered an error. Please try again later." = "The service encountered an error. Please try again later."; +"There was a sending your post to Tumblr." = "There was a sending your post to Tumblr."; + +"There was an error saving to Pinboard" = "There was an error saving to Pinboard"; + +"Sorry, Instapaper did not accept your credentials. Please try again." = "Sorry, Instapaper did not accept your credentials. Please try again."; +"Sorry, Instapaper encountered an error. Please try again." = "Sorry, Instapaper encountered an error. Please try again."; +"There was a problem saving to Instapaper." = "There was a problem saving to Instapaper."; + +"Incorrect username and password" = "Incorrect username and password"; +"There was an error logging into Google Reader" = "There was an error logging into Google Reader"; +"There was a problem authenticating your account." = "There was a problem authenticating your account."; +"There was a problem saving your note." = "There was a problem saving your note."; + +"There was a problem saving to Delicious." = "There was a problem saving to Delicious."; + +"Open in Safari" = "Open in Safari"; +"Attached: %@" = "Attached: %@"; + +"You must be online to login to %@" = "You must be online to login to %@"; + +"Auto Share" = "Auto Share"; +"Enable auto share to skip this step in the future." = "Enable auto share to skip this step in the future."; + +"You must be online in order to share with %@" = "You must be online in order to share with %@"; +"There was an error while sharing" = "There was an error while sharing"; + +"Could not authenticate you. Please relogin." = "Could not authenticate you. Please relogin."; +"There was a problem requesting authorization from %@" = "There was a problem requesting authorization from %@"; +"Request Error" = "Request Error"; +"There was an error while sharing" = "There was an error while sharing"; + +"Authorize Error" = "Authorize Error"; +"There was an error while authorizing" = "There was an error while authorizing"; + +"Authenticating..." = "Authenticating..."; +"There was a problem requesting access from %@" = "There was a problem requesting access from %@"; + +"Access Error" = "Access Error"; +"There was an error while sharing" = "There was an error while sharing"; \ No newline at end of file diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 8117453e..c2aa3565 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -45,7 +45,7 @@ // Facebook - http://www.facebook.com/developers // If SHKFacebookUseSessionProxy is enabled then SHKFacebookSecret is ignored and should be left blank -#define SHKFacebookUseSessionProxy NO +#define SHKFacebookUseSessionProxy NO #define SHKFacebookKey @"" #define SHKFacebookSecret @"" #define SHKFacebookSessionProxyURL @"" @@ -68,7 +68,7 @@ 1. Open your application settings at http://dev.twitter.com/apps/ 2. 'Application Type' should be set to BROWSER (not client) 3. 'Callback URL' should match whatever you enter in SHKTwitterCallbackUrl. The callback url doesn't have to be an actual existing url. The user will never get to it because ShareKit intercepts it before the user is redirected. It just needs to match. -*/ + */ #define SHKTwitterConsumerKey @"" #define SHKTwitterSecret @"" #define SHKTwitterCallbackUrl @"" // You need to set this if using OAuth, see note above (xAuth users can skip it) @@ -79,6 +79,11 @@ #define SHKBitLyLogin @"" #define SHKBitLyKey @"" +// ShareMenu Ordering +#define SHKShareMenuAlphabeticalOrder 1 // Setting this to 1 will show list in Alphabetical Order, setting to 0 will follow the order in SHKShares.plist + +// Append 'Shared With 'Signature to Email (and related forms) +#define SHKSharedWithSignature 0 @@ -108,8 +113,10 @@ #define SHKModalTransitionStyle @"UIModalTransitionStyleCoverVertical" // See: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle // ShareMenu Ordering -#define SHKShareMenuAlphabeticalOrder 0 // Setting this to 1 will show list in Alphabetical Order, setting to 0 will follow the order in SHKShares.plist +#define SHKShareMenuAlphabeticalOrder 1 // Setting this to 1 will show list in Alphabetical Order, setting to 0 will follow the order in SHKShares.plist +// Append 'Shared With 'Signature to Email (and related forms) +#define SHKSharedWithSignature 0 /* UI Configuration : Advanced diff --git a/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m b/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m index fc1eaeb9..910dc04c 100644 --- a/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m +++ b/Classes/ShareKit/Sharers/Actions/Copy/SHKCopy.m @@ -82,6 +82,10 @@ - (BOOL)send // Notify user [[SHKActivityIndicator currentIndicator] displayCompleted:SHKLocalizedString(@"Copied!")]; + // Notify delegate, but quietly + self.quiet = YES; + [self sendDidFinish]; + return YES; } diff --git a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m index 1f69b187..c94511c6 100644 --- a/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m +++ b/Classes/ShareKit/Sharers/Actions/Email/SHKMail.m @@ -103,6 +103,8 @@ - (BOOL)shouldAutoShare - (BOOL)send { + self.quiet = YES; + if (![self validateItem]) return NO; @@ -153,7 +155,11 @@ - (BOOL)sendMail body = @""; // sig - body = [body stringByAppendingFormat:@"

Sent from %@", SHKMyAppName]; + if (SHKSharedWithSignature) + { + body = [body stringByAppendingString:@"

"]; + body = [body stringByAppendingString:SHKLocalizedString(@"Sent from %@", SHKMyAppName)]; + } // save changes to body [item setCustomValue:body forKey:@"body"]; @@ -170,6 +176,22 @@ - (BOOL)sendMail - (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error { [[SHK currentHelper] hideCurrentViewControllerAnimated:YES]; + + switch (result) + { + case MFMailComposeResultSent: + [self sendDidFinish]; + break; + case MFMailComposeResultSaved: + [self sendDidFinish]; + break; + case MFMailComposeResultCancelled: + [self sendDidCancel]; + break; + case MFMailComposeResultFailed: + [self sendDidFailWithError:nil]; + break; + } } diff --git a/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m index 709d532b..489520f6 100644 --- a/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m +++ b/Classes/ShareKit/Sharers/Actions/Open in Safari/SHKSafari.m @@ -71,8 +71,12 @@ - (BOOL)shouldAutoShare - (BOOL)send { + self.quiet = YES; + [[UIApplication sharedApplication] openURL:item.URL]; + [self sendDidFinish]; + return YES; } diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index b0ec38bc..484e1da9 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -143,10 +143,10 @@ - (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest NSDictionary *formValues = [pendingForm formValues]; OARequestParameter *username = [[[OARequestParameter alloc] initWithName:@"x_auth_username" - value:SHKEncode([formValues objectForKey:@"username"])] autorelease]; + value:[formValues objectForKey:@"username"]] autorelease]; OARequestParameter *password = [[[OARequestParameter alloc] initWithName:@"x_auth_password" - value:SHKEncode([formValues objectForKey:@"password"])] autorelease]; + value:[formValues objectForKey:@"password"]] autorelease]; OARequestParameter *mode = [[[OARequestParameter alloc] initWithName:@"x_auth_mode" value:@"client_auth"] autorelease]; @@ -167,7 +167,11 @@ - (void)tokenAccessTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *) else { - [self tokenAccessTicket:ticket didFailWithError:[SHK error:[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]]]; + NSString *response = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + + SHKLog(@"tokenAccessTicket Response Body: %@", response); + + [self tokenAccessTicket:ticket didFailWithError:[SHK error:response]]; return; } } @@ -263,11 +267,17 @@ - (void)shortenURLFinished:(SHKRequest *)aRequest cancelButtonTitle:SHKLocalizedString(@"Continue") otherButtonTitles:nil] autorelease] show]; - [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.title, [item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] forKey:@"status"]; + [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.text ? item.text : item.title, [item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] forKey:@"status"]; } else - [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.title, result] forKey:@"status"]; + { + ///if already a bitly login, use url instead + if ([result isEqualToString:@"ALREADY_A_BITLY_LINK"]) + result = [item.URL.absoluteString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + + [item setCustomValue:[NSString stringWithFormat:@"%@ %@", item.text ? item.text : item.title, result] forKey:@"status"]; + } [self showTwitterForm]; } @@ -336,13 +346,47 @@ - (void)sendStatus - (void)sendStatusTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data { // TODO better error handling here - - + if (ticket.didSucceed) [self sendDidFinish]; else - [self sendDidFailWithError:nil]; + { + if (SHKDebugShowLogs) + SHKLog(@"Twitter Send Status Error: %@", [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); + + // CREDIT: Oliver Drobnik + + NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + + // in case our makeshift parsing does not yield an error message + NSString *errorMessage = @"Unknown Error"; + + NSScanner *scanner = [NSScanner scannerWithString:string]; + + // skip until error message + [scanner scanUpToString:@"\"error\":\"" intoString:nil]; + + + if ([scanner scanString:@"\"error\":\"" intoString:nil]) + { + // get the message until the closing double quotes + [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\""] intoString:&errorMessage]; + } + + + // this is the error message for revoked access + if ([errorMessage isEqualToString:@"Invalid / used nonce"]) + { + NSError *error = [NSError errorWithDomain:@"Twitter" code:1 userInfo:[NSDictionary dictionaryWithObject:@"Invalid Login" forKey:NSLocalizedDescriptionKey]]; + [self sendDidFailShouldRelogin]; + } + else + { + NSError *error = [NSError errorWithDomain:@"Twitter" code:2 userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]]; + [self sendDidFailWithError:error]; + } + } } - (void)sendStatusTicket:(OAServiceTicket *)ticket didFailWithError:(NSError*)error @@ -391,6 +435,11 @@ - (void)sendImage { CGFloat compression = 0.9f; NSData *imageData = UIImageJPEGRepresentation([item image], compression); + // TODO + // Note from Nate to creator of sendImage method - This seems like it could be a source of sluggishness. + // For example, if the image is large (say 3000px x 3000px for example), it would be better to resize the image + // to an appropriate size (max of img.ly) and then start trying to compress. + while ([imageData length] > 700000 && compression > 0.1) { // NSLog(@"Image size too big, compression more: current data size: %d bytes",[imageData length]); compression -= 0.1; diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m index 382f7331..565aaa3c 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitterForm.m @@ -69,7 +69,7 @@ - (void)loadView self.view.backgroundColor = [UIColor whiteColor]; - self.textView = [[UITextView alloc] initWithFrame:CGRectZero]; + self.textView = [[UITextView alloc] initWithFrame:self.view.bounds]; textView.delegate = self; textView.font = [UIFont systemFontOfSize:15]; textView.contentInset = UIEdgeInsetsMake(5,5,0,0); diff --git a/Classes/ShareKit/UI/SHKActionSheet.h b/Classes/ShareKit/UI/SHKActionSheet.h index a9db9da5..0d2d76b3 100644 --- a/Classes/ShareKit/UI/SHKActionSheet.h +++ b/Classes/ShareKit/UI/SHKActionSheet.h @@ -30,12 +30,12 @@ @interface SHKActionSheet : UIActionSheet { - NSArray *sharers; + NSMutableArray *sharers; SHKItem *item; } -@property (retain) NSArray *sharers; +@property (retain) NSMutableArray *sharers; @property (retain) SHKItem *item; diff --git a/Classes/ShareKit/UI/SHKActionSheet.m b/Classes/ShareKit/UI/SHKActionSheet.m index 47d73101..8921a7a8 100644 --- a/Classes/ShareKit/UI/SHKActionSheet.m +++ b/Classes/ShareKit/UI/SHKActionSheet.m @@ -52,15 +52,19 @@ + (SHKActionSheet *)actionSheetForType:(SHKShareType)type as.item = [[[SHKItem alloc] init] autorelease]; as.item.shareType = type; - as.sharers = [SHK favoriteSharersForType:type]; - - // Add buttons for each favoriate sharer + as.sharers = [NSMutableArray arrayWithCapacity:0]; + NSArray *favoriteSharers = [SHK favoriteSharersForType:type]; + + // Add buttons for each favorite sharer id class; - for(NSString *sharerId in as.sharers) + for(NSString *sharerId in favoriteSharers) { class = NSClassFromString(sharerId); if ([class canShare]) + { [as addButtonWithTitle: [class sharerTitle] ]; + [as.sharers addObject:sharerId]; + } } // Add More button diff --git a/Classes/ShareKit/UI/SHKFormFieldCell.m b/Classes/ShareKit/UI/SHKFormFieldCell.m index f8edc66b..8a97abb2 100644 --- a/Classes/ShareKit/UI/SHKFormFieldCell.m +++ b/Classes/ShareKit/UI/SHKFormFieldCell.m @@ -58,6 +58,7 @@ - (UITextField *)getTextField textField.font = [UIFont systemFontOfSize:17]; textField.textColor = [UIColor darkGrayColor]; textField.autocapitalizationType = UITextAutocapitalizationTypeNone; + textField.autocorrectionType = UITextAutocorrectionTypeNo; textField.delegate = form; [self.contentView addSubview:textField]; [textField release]; @@ -74,8 +75,6 @@ - (void)layoutSubviews if (settings.type == SHKFormFieldTypeText || settings.type == SHKFormFieldTypePassword) { self.textField.secureTextEntry = settings.type == SHKFormFieldTypePassword; - self.textField.autocorrectionType = UITextAutocorrectionTypeNo; - self.textField.autocapitalizationType = UITextAutocapitalizationTypeNone; textField.frame = CGRectMake(labelWidth + SHK_FORM_CELL_PAD_LEFT, 2 + round(self.contentView.bounds.size.height/2 - textField.bounds.size.height/2), diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index df374080..97079860 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -87,7 +87,7 @@ 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */ = {isa = PBXBuildFile; fileRef = 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */; }; 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; 43EF406E11D3FFF800B1F700 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43EF406D11D3FFF800B1F700 /* Security.framework */; }; - 78AC69D412194C110038D228 /* ShareKit.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 78AC69D312194C110038D228 /* ShareKit.bundle */; }; + 43FF9C7412270E9F00ADE53C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 43FF9C7212270E9F00ADE53C /* Localizable.strings */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -243,7 +243,8 @@ 43C91DF411EBAE4800F31FAE /* SHKTumblr.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKTumblr.m; sourceTree = ""; }; 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 43EF406D11D3FFF800B1F700 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; - 78AC69D312194C110038D228 /* ShareKit.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = ShareKit.bundle; sourceTree = ""; }; + 43FF9C7312270E9F00ADE53C /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = Classes/ShareKit/Localization/en.lproj/Localizable.strings; sourceTree = SOURCE_ROOT; }; + 43FF9C7512270EB900ADE53C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Classes/ShareKit/Localization/de.lproj/Localizable.strings; sourceTree = SOURCE_ROOT; }; 8D1107310486CEB800E47090 /* ShareKit-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ShareKit-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -306,7 +307,6 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( - 78AC69D312194C110038D228 /* ShareKit.bundle */, 43A5382611DBE480004A1712 /* example.pdf */, 43A5382711DBE480004A1712 /* sanFran.jpg */, 28F335F01007B36200424DE2 /* RootViewController.xib */, @@ -392,6 +392,7 @@ 43A5367311DBE3B9004A1712 /* Base Sharer Classes */, 43A5367811DBE3B9004A1712 /* Categories */, 43A5367B11DBE3B9004A1712 /* Helpers */, + 43FF9C7112270E7F00ADE53C /* Localization */, ); path = Core; sourceTree = ""; @@ -721,6 +722,14 @@ path = Tumblr; sourceTree = ""; }; + 43FF9C7112270E7F00ADE53C /* Localization */ = { + isa = PBXGroup; + children = ( + 43FF9C7212270E9F00ADE53C /* Localizable.strings */, + ); + name = Localization; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -748,7 +757,6 @@ isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ShareKit" */; compatibilityVersion = "Xcode 3.1"; - developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, @@ -779,7 +787,7 @@ 43A5382811DBE480004A1712 /* example.pdf in Resources */, 43A5382911DBE480004A1712 /* sanFran.jpg in Resources */, 43C91D1D11EB963600F31FAE /* MainWindow-iPad.xib in Resources */, - 78AC69D412194C110038D228 /* ShareKit.bundle in Resources */, + 43FF9C7412270E9F00ADE53C /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -862,6 +870,18 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXVariantGroup section */ + 43FF9C7212270E9F00ADE53C /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 43FF9C7312270E9F00ADE53C /* en */, + 43FF9C7512270EB900ADE53C /* de */, + ); + name = Localizable.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ 1D6058940D05DD3E006BFB54 /* Debug */ = { isa = XCBuildConfiguration; @@ -876,6 +896,7 @@ INFOPLIST_FILE = "ShareKit-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 3.2; PRODUCT_NAME = ShareKit; + SDKROOT = iphoneos4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -891,6 +912,7 @@ INFOPLIST_FILE = "ShareKit-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 3.2; PRODUCT_NAME = ShareKit; + SDKROOT = iphoneos4.1; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -906,7 +928,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 3.1; PREBINDING = NO; - SDKROOT = iphoneos4.1; + SDKROOT = iphoneos4.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; From 095b2c925b74adb1f2f9fbb3169736f3b16a5474 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Thu, 26 Aug 2010 14:35:17 -0700 Subject: [PATCH 38/50] cleanup --- .../NSMutableURLRequest+Parameters.h | 35 --- .../NSMutableURLRequest+Parameters.m | 97 -------- .../OAuth/Categories/NSString+URLEncoding.h | 34 --- .../OAuth/Categories/NSString+URLEncoding.m | 52 ---- Classes/OAuth/Categories/NSURL+Base.h | 34 --- Classes/OAuth/Categories/NSURL+Base.m | 38 --- Classes/OAuth/Crytpo/Base64Transcoder.c | 230 ----------------- Classes/OAuth/Crytpo/Base64Transcoder.h | 36 --- Classes/OAuth/Crytpo/hmac.c | 86 ------- Classes/OAuth/Crytpo/hmac.h | 31 --- Classes/OAuth/Crytpo/sha1.c | 169 ------------- Classes/OAuth/Crytpo/sha1.h | 12 - Classes/OAuth/OAAsynchronousDataFetcher.h | 45 ---- Classes/OAuth/OAAsynchronousDataFetcher.m | 134 ---------- Classes/OAuth/OAConsumer.h | 40 --- Classes/OAuth/OAConsumer.m | 51 ---- Classes/OAuth/OADataFetcher.h | 45 ---- Classes/OAuth/OADataFetcher.m | 65 ----- Classes/OAuth/OAHMAC_SHA1SignatureProvider.h | 32 --- Classes/OAuth/OAHMAC_SHA1SignatureProvider.m | 58 ----- Classes/OAuth/OAMutableURLRequest.h | 68 ------ Classes/OAuth/OAMutableURLRequest.m | 231 ------------------ Classes/OAuth/OAPlaintextSignatureProvider.h | 31 --- Classes/OAuth/OAPlaintextSignatureProvider.m | 43 ---- Classes/OAuth/OAProblem.h | 53 ---- Classes/OAuth/OAProblem.m | 165 ------------- Classes/OAuth/OARequestParameter.h | 45 ---- Classes/OAuth/OARequestParameter.m | 70 ------ Classes/OAuth/OAServiceTicket.h | 47 ---- Classes/OAuth/OAServiceTicket.m | 56 ----- Classes/OAuth/OASignatureProviding.h | 34 --- Classes/OAuth/OAToken.h | 41 ---- Classes/OAuth/OAToken.m | 105 -------- Classes/OAuth/OAuthConsumer.h | 39 --- ShareKit.bundle/de.lproj/Localizable.strings | Bin 8220 -> 0 bytes ShareKit.bundle/en.lproj/Localizable.strings | Bin 7834 -> 0 bytes 36 files changed, 2352 deletions(-) delete mode 100755 Classes/OAuth/Categories/NSMutableURLRequest+Parameters.h delete mode 100755 Classes/OAuth/Categories/NSMutableURLRequest+Parameters.m delete mode 100755 Classes/OAuth/Categories/NSString+URLEncoding.h delete mode 100755 Classes/OAuth/Categories/NSString+URLEncoding.m delete mode 100755 Classes/OAuth/Categories/NSURL+Base.h delete mode 100755 Classes/OAuth/Categories/NSURL+Base.m delete mode 100755 Classes/OAuth/Crytpo/Base64Transcoder.c delete mode 100755 Classes/OAuth/Crytpo/Base64Transcoder.h delete mode 100755 Classes/OAuth/Crytpo/hmac.c delete mode 100755 Classes/OAuth/Crytpo/hmac.h delete mode 100755 Classes/OAuth/Crytpo/sha1.c delete mode 100755 Classes/OAuth/Crytpo/sha1.h delete mode 100644 Classes/OAuth/OAAsynchronousDataFetcher.h delete mode 100644 Classes/OAuth/OAAsynchronousDataFetcher.m delete mode 100755 Classes/OAuth/OAConsumer.h delete mode 100755 Classes/OAuth/OAConsumer.m delete mode 100755 Classes/OAuth/OADataFetcher.h delete mode 100755 Classes/OAuth/OADataFetcher.m delete mode 100755 Classes/OAuth/OAHMAC_SHA1SignatureProvider.h delete mode 100755 Classes/OAuth/OAHMAC_SHA1SignatureProvider.m delete mode 100755 Classes/OAuth/OAMutableURLRequest.h delete mode 100755 Classes/OAuth/OAMutableURLRequest.m delete mode 100755 Classes/OAuth/OAPlaintextSignatureProvider.h delete mode 100755 Classes/OAuth/OAPlaintextSignatureProvider.m delete mode 100755 Classes/OAuth/OAProblem.h delete mode 100755 Classes/OAuth/OAProblem.m delete mode 100755 Classes/OAuth/OARequestParameter.h delete mode 100755 Classes/OAuth/OARequestParameter.m delete mode 100755 Classes/OAuth/OAServiceTicket.h delete mode 100755 Classes/OAuth/OAServiceTicket.m delete mode 100755 Classes/OAuth/OASignatureProviding.h delete mode 100755 Classes/OAuth/OAToken.h delete mode 100755 Classes/OAuth/OAToken.m delete mode 100755 Classes/OAuth/OAuthConsumer.h delete mode 100644 ShareKit.bundle/de.lproj/Localizable.strings delete mode 100644 ShareKit.bundle/en.lproj/Localizable.strings diff --git a/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.h b/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.h deleted file mode 100755 index 13bf9afa..00000000 --- a/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// NSMutableURLRequest+Parameters.h -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "OARequestParameter.h" -#import "NSURL+Base.h" - - -@interface NSMutableURLRequest (OAParameterAdditions) - -- (NSArray *)parameters; -- (void)setParameters:(NSArray *)parameters; - -@end diff --git a/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.m b/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.m deleted file mode 100755 index 24035ed8..00000000 --- a/Classes/OAuth/Categories/NSMutableURLRequest+Parameters.m +++ /dev/null @@ -1,97 +0,0 @@ -// -// NSMutableURLRequest+Parameters.m -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "NSMutableURLRequest+Parameters.h" - - -@implementation NSMutableURLRequest (OAParameterAdditions) - -- (NSArray *)parameters -{ - NSString *encodedParameters; - BOOL shouldfree = NO; - - if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) - encodedParameters = [[self URL] query]; - else - { - // POST, PUT - shouldfree = YES; - encodedParameters = [[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding]; - } - - if ((encodedParameters == nil) || ([encodedParameters isEqualToString:@""])) - { - if (shouldfree) - [encodedParameters release]; - - return nil; - } - - NSArray *encodedParameterPairs = [encodedParameters componentsSeparatedByString:@"&"]; - NSMutableArray *requestParameters = [[[NSMutableArray alloc] initWithCapacity:16] autorelease]; - - for (NSString *encodedPair in encodedParameterPairs) - { - NSArray *encodedPairElements = [encodedPair componentsSeparatedByString:@"="]; - OARequestParameter *parameter = [OARequestParameter requestParameterWithName:[[encodedPairElements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] - value:[[encodedPairElements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - [requestParameters addObject:parameter]; - } - - // Cleanup - if (shouldfree) - [encodedParameters release]; - - return requestParameters; -} - -- (void)setParameters:(NSArray *)parameters -{ - NSMutableString *encodedParameterPairs = [NSMutableString stringWithCapacity:256]; - - int position = 1; - for (OARequestParameter *requestParameter in parameters) - { - [encodedParameterPairs appendString:[requestParameter URLEncodedNameValuePair]]; - if (position < [parameters count]) - [encodedParameterPairs appendString:@"&"]; - - position++; - } - - if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) - [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", [[self URL] URLStringWithoutQuery], encodedParameterPairs]]]; - else - { - // POST, PUT - NSData *postData = [encodedParameterPairs dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; - [self setHTTPBody:postData]; - [self setValue:[NSString stringWithFormat:@"%d", [postData length]] forHTTPHeaderField:@"Content-Length"]; - [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; - } -} - -@end diff --git a/Classes/OAuth/Categories/NSString+URLEncoding.h b/Classes/OAuth/Categories/NSString+URLEncoding.h deleted file mode 100755 index de06fe77..00000000 --- a/Classes/OAuth/Categories/NSString+URLEncoding.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// NSString+URLEncoding.h -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import - - -@interface NSString (OAURLEncodingAdditions) - -- (NSString *)URLEncodedString; -- (NSString *)URLDecodedString; - -@end diff --git a/Classes/OAuth/Categories/NSString+URLEncoding.m b/Classes/OAuth/Categories/NSString+URLEncoding.m deleted file mode 100755 index 540492de..00000000 --- a/Classes/OAuth/Categories/NSString+URLEncoding.m +++ /dev/null @@ -1,52 +0,0 @@ -// -// NSString+URLEncoding.m -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "NSString+URLEncoding.h" - - -@implementation NSString (OAURLEncodingAdditions) - -- (NSString *)URLEncodedString -{ - NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, - (CFStringRef)self, - NULL, - CFSTR("!*'();:@&=+$,/?%#[]"), - kCFStringEncodingUTF8); - [result autorelease]; - return result; -} - -- (NSString*)URLDecodedString -{ - NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, - (CFStringRef)self, - CFSTR(""), - kCFStringEncodingUTF8); - [result autorelease]; - return result; -} - -@end diff --git a/Classes/OAuth/Categories/NSURL+Base.h b/Classes/OAuth/Categories/NSURL+Base.h deleted file mode 100755 index 5d12b696..00000000 --- a/Classes/OAuth/Categories/NSURL+Base.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// NSURL+Base.h -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import - - -@interface NSURL (OABaseAdditions) - -- (NSString *)URLStringWithoutQuery; - -@end diff --git a/Classes/OAuth/Categories/NSURL+Base.m b/Classes/OAuth/Categories/NSURL+Base.m deleted file mode 100755 index 8d4d4209..00000000 --- a/Classes/OAuth/Categories/NSURL+Base.m +++ /dev/null @@ -1,38 +0,0 @@ -// -// NSURL+Base.m -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "NSURL+Base.h" - - -@implementation NSURL (OABaseAdditions) - -- (NSString *)URLStringWithoutQuery -{ - NSArray *parts = [[self absoluteString] componentsSeparatedByString:@"?"]; - return [parts objectAtIndex:0]; -} - -@end diff --git a/Classes/OAuth/Crytpo/Base64Transcoder.c b/Classes/OAuth/Crytpo/Base64Transcoder.c deleted file mode 100755 index a655581e..00000000 --- a/Classes/OAuth/Crytpo/Base64Transcoder.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Base64Transcoder.c - * Base64Test - * - * Created by Jonathan Wight on Tue Mar 18 2003. - * Copyright (c) 2003 Toxic Software. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#include "Base64Transcoder.h" - -#include -#include - -const u_int8_t kBase64EncodeTable[64] = { - /* 0 */ 'A', /* 1 */ 'B', /* 2 */ 'C', /* 3 */ 'D', - /* 4 */ 'E', /* 5 */ 'F', /* 6 */ 'G', /* 7 */ 'H', - /* 8 */ 'I', /* 9 */ 'J', /* 10 */ 'K', /* 11 */ 'L', - /* 12 */ 'M', /* 13 */ 'N', /* 14 */ 'O', /* 15 */ 'P', - /* 16 */ 'Q', /* 17 */ 'R', /* 18 */ 'S', /* 19 */ 'T', - /* 20 */ 'U', /* 21 */ 'V', /* 22 */ 'W', /* 23 */ 'X', - /* 24 */ 'Y', /* 25 */ 'Z', /* 26 */ 'a', /* 27 */ 'b', - /* 28 */ 'c', /* 29 */ 'd', /* 30 */ 'e', /* 31 */ 'f', - /* 32 */ 'g', /* 33 */ 'h', /* 34 */ 'i', /* 35 */ 'j', - /* 36 */ 'k', /* 37 */ 'l', /* 38 */ 'm', /* 39 */ 'n', - /* 40 */ 'o', /* 41 */ 'p', /* 42 */ 'q', /* 43 */ 'r', - /* 44 */ 's', /* 45 */ 't', /* 46 */ 'u', /* 47 */ 'v', - /* 48 */ 'w', /* 49 */ 'x', /* 50 */ 'y', /* 51 */ 'z', - /* 52 */ '0', /* 53 */ '1', /* 54 */ '2', /* 55 */ '3', - /* 56 */ '4', /* 57 */ '5', /* 58 */ '6', /* 59 */ '7', - /* 60 */ '8', /* 61 */ '9', /* 62 */ '+', /* 63 */ '/' -}; - -/* --1 = Base64 end of data marker. --2 = White space (tabs, cr, lf, space) --3 = Noise (all non whitespace, non-base64 characters) --4 = Dangerous noise --5 = Illegal noise (null byte) -*/ - -const int8_t kBase64DecodeTable[128] = { - /* 0x00 */ -5, /* 0x01 */ -3, /* 0x02 */ -3, /* 0x03 */ -3, - /* 0x04 */ -3, /* 0x05 */ -3, /* 0x06 */ -3, /* 0x07 */ -3, - /* 0x08 */ -3, /* 0x09 */ -2, /* 0x0a */ -2, /* 0x0b */ -2, - /* 0x0c */ -2, /* 0x0d */ -2, /* 0x0e */ -3, /* 0x0f */ -3, - /* 0x10 */ -3, /* 0x11 */ -3, /* 0x12 */ -3, /* 0x13 */ -3, - /* 0x14 */ -3, /* 0x15 */ -3, /* 0x16 */ -3, /* 0x17 */ -3, - /* 0x18 */ -3, /* 0x19 */ -3, /* 0x1a */ -3, /* 0x1b */ -3, - /* 0x1c */ -3, /* 0x1d */ -3, /* 0x1e */ -3, /* 0x1f */ -3, - /* ' ' */ -2, /* '!' */ -3, /* '"' */ -3, /* '#' */ -3, - /* '$' */ -3, /* '%' */ -3, /* '&' */ -3, /* ''' */ -3, - /* '(' */ -3, /* ')' */ -3, /* '*' */ -3, /* '+' */ 62, - /* ',' */ -3, /* '-' */ -3, /* '.' */ -3, /* '/' */ 63, - /* '0' */ 52, /* '1' */ 53, /* '2' */ 54, /* '3' */ 55, - /* '4' */ 56, /* '5' */ 57, /* '6' */ 58, /* '7' */ 59, - /* '8' */ 60, /* '9' */ 61, /* ':' */ -3, /* ';' */ -3, - /* '<' */ -3, /* '=' */ -1, /* '>' */ -3, /* '?' */ -3, - /* '@' */ -3, /* 'A' */ 0, /* 'B' */ 1, /* 'C' */ 2, - /* 'D' */ 3, /* 'E' */ 4, /* 'F' */ 5, /* 'G' */ 6, - /* 'H' */ 7, /* 'I' */ 8, /* 'J' */ 9, /* 'K' */ 10, - /* 'L' */ 11, /* 'M' */ 12, /* 'N' */ 13, /* 'O' */ 14, - /* 'P' */ 15, /* 'Q' */ 16, /* 'R' */ 17, /* 'S' */ 18, - /* 'T' */ 19, /* 'U' */ 20, /* 'V' */ 21, /* 'W' */ 22, - /* 'X' */ 23, /* 'Y' */ 24, /* 'Z' */ 25, /* '[' */ -3, - /* '\' */ -3, /* ']' */ -3, /* '^' */ -3, /* '_' */ -3, - /* '`' */ -3, /* 'a' */ 26, /* 'b' */ 27, /* 'c' */ 28, - /* 'd' */ 29, /* 'e' */ 30, /* 'f' */ 31, /* 'g' */ 32, - /* 'h' */ 33, /* 'i' */ 34, /* 'j' */ 35, /* 'k' */ 36, - /* 'l' */ 37, /* 'm' */ 38, /* 'n' */ 39, /* 'o' */ 40, - /* 'p' */ 41, /* 'q' */ 42, /* 'r' */ 43, /* 's' */ 44, - /* 't' */ 45, /* 'u' */ 46, /* 'v' */ 47, /* 'w' */ 48, - /* 'x' */ 49, /* 'y' */ 50, /* 'z' */ 51, /* '{' */ -3, - /* '|' */ -3, /* '}' */ -3, /* '~' */ -3, /* 0x7f */ -3 -}; - -const u_int8_t kBits_00000011 = 0x03; -const u_int8_t kBits_00001111 = 0x0F; -const u_int8_t kBits_00110000 = 0x30; -const u_int8_t kBits_00111100 = 0x3C; -const u_int8_t kBits_00111111 = 0x3F; -const u_int8_t kBits_11000000 = 0xC0; -const u_int8_t kBits_11110000 = 0xF0; -const u_int8_t kBits_11111100 = 0xFC; - -size_t EstimateBas64EncodedDataSize(size_t inDataSize) -{ -size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4; -theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72; -return(theEncodedDataSize); -} - -size_t EstimateBas64DecodedDataSize(size_t inDataSize) -{ -size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3; -//theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72; -return(theDecodedDataSize); -} - -bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize) -{ -size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize); -if (*ioOutputDataSize < theEncodedDataSize) - return(false); -*ioOutputDataSize = theEncodedDataSize; -const u_int8_t *theInPtr = (const u_int8_t *)inInputData; -u_int32_t theInIndex = 0, theOutIndex = 0; -for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3) - { - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6]; - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0]; - if (theOutIndex % 74 == 72) - { - outOutputData[theOutIndex++] = '\r'; - outOutputData[theOutIndex++] = '\n'; - } - } -const size_t theRemainingBytes = inInputDataSize - theInIndex; -if (theRemainingBytes == 1) - { - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4]; - outOutputData[theOutIndex++] = '='; - outOutputData[theOutIndex++] = '='; - if (theOutIndex % 74 == 72) - { - outOutputData[theOutIndex++] = '\r'; - outOutputData[theOutIndex++] = '\n'; - } - } -else if (theRemainingBytes == 2) - { - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; - outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6]; - outOutputData[theOutIndex++] = '='; - if (theOutIndex % 74 == 72) - { - outOutputData[theOutIndex++] = '\r'; - outOutputData[theOutIndex++] = '\n'; - } - } -return(true); -} - -bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize) -{ -memset(ioOutputData, '.', *ioOutputDataSize); - -size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize); -if (*ioOutputDataSize < theDecodedDataSize) - return(false); -*ioOutputDataSize = 0; -const u_int8_t *theInPtr = (const u_int8_t *)inInputData; -u_int8_t *theOutPtr = (u_int8_t *)ioOutputData; -size_t theInIndex = 0, theOutIndex = 0; -u_int8_t theOutputOctet; -size_t theSequence = 0; -for (; theInIndex < inInputDataSize; ) - { - int8_t theSextet = 0; - - int8_t theCurrentInputOctet = theInPtr[theInIndex]; - theSextet = kBase64DecodeTable[theCurrentInputOctet]; - if (theSextet == -1) - break; - while (theSextet == -2) - { - theCurrentInputOctet = theInPtr[++theInIndex]; - theSextet = kBase64DecodeTable[theCurrentInputOctet]; - } - while (theSextet == -3) - { - theCurrentInputOctet = theInPtr[++theInIndex]; - theSextet = kBase64DecodeTable[theCurrentInputOctet]; - } - if (theSequence == 0) - { - theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100; - } - else if (theSequence == 1) - { - theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011; - theOutPtr[theOutIndex++] = theOutputOctet; - } - else if (theSequence == 2) - { - theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000; - } - else if (theSequence == 3) - { - theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111; - theOutPtr[theOutIndex++] = theOutputOctet; - } - else if (theSequence == 4) - { - theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000; - } - else if (theSequence == 5) - { - theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111; - theOutPtr[theOutIndex++] = theOutputOctet; - } - theSequence = (theSequence + 1) % 6; - if (theSequence != 2 && theSequence != 4) - theInIndex++; - } -*ioOutputDataSize = theOutIndex; -return(true); -} diff --git a/Classes/OAuth/Crytpo/Base64Transcoder.h b/Classes/OAuth/Crytpo/Base64Transcoder.h deleted file mode 100755 index 87520989..00000000 --- a/Classes/OAuth/Crytpo/Base64Transcoder.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Base64Transcoder.h - * Base64Test - * - * Created by Jonathan Wight on Tue Mar 18 2003. - * Copyright (c) 2003 Toxic Software. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - */ - -#include -#include - -extern size_t EstimateBas64EncodedDataSize(size_t inDataSize); -extern size_t EstimateBas64DecodedDataSize(size_t inDataSize); - -extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize); -extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize); - diff --git a/Classes/OAuth/Crytpo/hmac.c b/Classes/OAuth/Crytpo/hmac.c deleted file mode 100755 index eea9a707..00000000 --- a/Classes/OAuth/Crytpo/hmac.c +++ /dev/null @@ -1,86 +0,0 @@ -// -// hmac.c -// OAuthConsumer -// -// Created by Jonathan Wight on 4/8/8. -// Copyright 2008 Jonathan Wight. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -/* - * Implementation of HMAC-SHA1. Adapted from example at http://tools.ietf.org/html/rfc2104 - - */ - -#include "sha1.h" - -#include -#include - -void hmac_sha1(const unsigned char *inText, size_t inTextLength, unsigned char* inKey, size_t inKeyLength, unsigned char *outDigest) -{ -const size_t B = 64; -const size_t L = 20; - -SHA1_CTX theSHA1Context; -unsigned char k_ipad[B + 1]; /* inner padding - key XORd with ipad */ -unsigned char k_opad[B + 1]; /* outer padding - key XORd with opad */ - -/* if key is longer than 64 bytes reset it to key=SHA1 (key) */ -if (inKeyLength > B) - { - SHA1Init(&theSHA1Context); - SHA1Update(&theSHA1Context, inKey, inKeyLength); - SHA1Final(inKey, &theSHA1Context); - inKeyLength = L; - } - -/* start out by storing key in pads */ -memset(k_ipad, 0, sizeof k_ipad); -memset(k_opad, 0, sizeof k_opad); -memcpy(k_ipad, inKey, inKeyLength); -memcpy(k_opad, inKey, inKeyLength); - -/* XOR key with ipad and opad values */ -int i; -for (i = 0; i < B; i++) - { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - -/* -* perform inner SHA1 -*/ -SHA1Init(&theSHA1Context); /* init context for 1st pass */ -SHA1Update(&theSHA1Context, k_ipad, B); /* start with inner pad */ -SHA1Update(&theSHA1Context, (unsigned char *)inText, inTextLength); /* then text of datagram */ -SHA1Final((unsigned char *)outDigest, &theSHA1Context); /* finish up 1st pass */ - -/* -* perform outer SHA1 -*/ -SHA1Init(&theSHA1Context); /* init context for 2nd -* pass */ -SHA1Update(&theSHA1Context, k_opad, B); /* start with outer pad */ -SHA1Update(&theSHA1Context, outDigest, L); /* then results of 1st -* hash */ -SHA1Final(outDigest, &theSHA1Context); /* finish up 2nd pass */ - -} \ No newline at end of file diff --git a/Classes/OAuth/Crytpo/hmac.h b/Classes/OAuth/Crytpo/hmac.h deleted file mode 100755 index 51eca9f6..00000000 --- a/Classes/OAuth/Crytpo/hmac.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// hmac.h -// OAuthConsumer -// -// Created by Jonathan Wight on 4/8/8. -// Copyright 2008 Jonathan Wight. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#ifndef HMAC_H -#define HMAC_H 1 - -extern void hmac_sha1(const unsigned char *inText, int inTextLength, unsigned char* inKey, const unsigned int inKeyLength, unsigned char *outDigest); - -#endif /* HMAC_H */ \ No newline at end of file diff --git a/Classes/OAuth/Crytpo/sha1.c b/Classes/OAuth/Crytpo/sha1.c deleted file mode 100755 index 16f5dbcf..00000000 --- a/Classes/OAuth/Crytpo/sha1.c +++ /dev/null @@ -1,169 +0,0 @@ -/* -SHA-1 in C -By Steve Reid -100% Public Domain - -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd if true. */ -#if __LITTLE_ENDIAN__ -#define LITTLE_ENDIAN -#endif -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -#include -#include - -#include "sha1.h" - -void SHA1Transform(unsigned long state[5], unsigned char buffer[64]); - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#ifdef LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#else -#define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1Transform(unsigned long state[5], unsigned char buffer[64]) -{ -unsigned long a, b, c, d, e; -typedef union { - unsigned char c[64]; - unsigned long l[16]; -} CHAR64LONG16; -CHAR64LONG16* block; -#ifdef SHA1HANDSOFF -static unsigned char workspace[64]; - block = (CHAR64LONG16*)workspace; - memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16*)buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init(SHA1_CTX* context) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len) -{ -unsigned int i, j; - - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1Final(unsigned char digest[20], SHA1_CTX* context) -{ -unsigned long i, j; -unsigned char finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1Update(context, (unsigned char *)"\200", 1); - while ((context->count[0] & 504) != 448) { - SHA1Update(context, (unsigned char *)"\0", 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - i = j = 0; - memset(context->buffer, 0, 64); - memset(context->state, 0, 20); - memset(context->count, 0, 8); - memset(&finalcount, 0, 8); -#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ - SHA1Transform(context->state, context->buffer); -#endif -} diff --git a/Classes/OAuth/Crytpo/sha1.h b/Classes/OAuth/Crytpo/sha1.h deleted file mode 100755 index f3218ee5..00000000 --- a/Classes/OAuth/Crytpo/sha1.h +++ /dev/null @@ -1,12 +0,0 @@ - -// From http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/sha1.c - -typedef struct { - unsigned long state[5]; - unsigned long count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -extern void SHA1Init(SHA1_CTX* context); -extern void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); -extern void SHA1Final(unsigned char digest[20], SHA1_CTX* context); diff --git a/Classes/OAuth/OAAsynchronousDataFetcher.h b/Classes/OAuth/OAAsynchronousDataFetcher.h deleted file mode 100644 index 20a23152..00000000 --- a/Classes/OAuth/OAAsynchronousDataFetcher.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// OAAsynchronousDataFetcher.h -// OAuthConsumer -// -// Created by Zsombor Szabó on 12/3/08. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import - -#import "OAMutableURLRequest.h" - -@interface OAAsynchronousDataFetcher : NSObject { - OAMutableURLRequest *request; - NSHTTPURLResponse *response; - NSURLConnection *connection; - NSMutableData *responseData; - id delegate; - SEL didFinishSelector; - SEL didFailSelector; -} - -+ (id)asynchronousFetcherWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; -- (id)initWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; - -- (void)start; -- (void)cancel; - -@end diff --git a/Classes/OAuth/OAAsynchronousDataFetcher.m b/Classes/OAuth/OAAsynchronousDataFetcher.m deleted file mode 100644 index 58472bc8..00000000 --- a/Classes/OAuth/OAAsynchronousDataFetcher.m +++ /dev/null @@ -1,134 +0,0 @@ -// -// OAAsynchronousDataFetcher.m -// OAuthConsumer -// -// Created by Zsombor Szabó on 12/3/08. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "OAAsynchronousDataFetcher.h" - -#import "OAServiceTicket.h" - -@implementation OAAsynchronousDataFetcher - -+ (id)asynchronousFetcherWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector -{ - return [[[OAAsynchronousDataFetcher alloc] initWithRequest:aRequest delegate:aDelegate didFinishSelector:finishSelector didFailSelector:failSelector] autorelease]; -} - -- (id)initWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector -{ - if (self = [super init]) - { - request = [aRequest retain]; - delegate = aDelegate; - didFinishSelector = finishSelector; - didFailSelector = failSelector; - } - return self; -} - -- (void)start -{ - [request prepare]; - - if (connection) - [connection release]; - - connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; - - if (connection) - { - if (responseData) - [responseData release]; - responseData = [[NSMutableData data] retain]; - } - else - { - OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request - response:nil - didSucceed:NO]; - [delegate performSelector:didFailSelector - withObject:ticket - withObject:nil]; - [ticket release]; - } -} - -- (void)cancel -{ - if (connection) - { - [connection cancel]; - [connection release]; - connection = nil; - } -} - -- (void)dealloc -{ - if (request) [request release]; - if (connection) [connection release]; - if (response) [response release]; - if (responseData) [responseData release]; - [super dealloc]; -} - -#pragma mark - -#pragma mark NSURLConnection methods - -- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)aResponse -{ - if (response) - [response release]; - response = [aResponse retain]; - [responseData setLength:0]; -} - -- (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)data -{ - [responseData appendData:data]; -} - -- (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error -{ - OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request - response:response - didSucceed:NO]; - [delegate performSelector:didFailSelector - withObject:ticket - withObject:error]; - - [ticket release]; -} - -- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection -{ - OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request - response:response - didSucceed:[(NSHTTPURLResponse *)response statusCode] < 400]; - [delegate performSelector:didFinishSelector - withObject:ticket - withObject:responseData]; - - [ticket release]; -} - -@end diff --git a/Classes/OAuth/OAConsumer.h b/Classes/OAuth/OAConsumer.h deleted file mode 100755 index 73bdab65..00000000 --- a/Classes/OAuth/OAConsumer.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// OAConsumer.h -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import - - -@interface OAConsumer : NSObject { -@protected - NSString *key; - NSString *secret; -} -@property(retain) NSString *key; -@property(retain) NSString *secret; - -- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; - -@end diff --git a/Classes/OAuth/OAConsumer.m b/Classes/OAuth/OAConsumer.m deleted file mode 100755 index 0582ad9d..00000000 --- a/Classes/OAuth/OAConsumer.m +++ /dev/null @@ -1,51 +0,0 @@ -// -// OAConsumer.m -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "OAConsumer.h" - - -@implementation OAConsumer -@synthesize key, secret; - -#pragma mark init - -- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret -{ - if (self = [super init]) - { - self.key = aKey; - self.secret = aSecret; - } - return self; -} - -- (void)dealloc -{ - [key release]; - [secret release]; - [super dealloc]; -} - -@end diff --git a/Classes/OAuth/OADataFetcher.h b/Classes/OAuth/OADataFetcher.h deleted file mode 100755 index 74273e37..00000000 --- a/Classes/OAuth/OADataFetcher.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// OADataFetcher.h -// OAuthConsumer -// -// Created by Jon Crosby on 11/5/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "OAMutableURLRequest.h" -#import "OAServiceTicket.h" - - -@interface OADataFetcher : NSObject { -@private - OAMutableURLRequest *request; - NSHTTPURLResponse *response; - NSURLConnection *connection; - NSError *error; - NSData *responseData; - id delegate; - SEL didFinishSelector; - SEL didFailSelector; -} - -- (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; - -@end diff --git a/Classes/OAuth/OADataFetcher.m b/Classes/OAuth/OADataFetcher.m deleted file mode 100755 index b9c6d67c..00000000 --- a/Classes/OAuth/OADataFetcher.m +++ /dev/null @@ -1,65 +0,0 @@ -// -// OADataFetcher.m -// OAuthConsumer -// -// Created by Jon Crosby on 11/5/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "OADataFetcher.h" - - -@implementation OADataFetcher - -- (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest - delegate:(id)aDelegate - didFinishSelector:(SEL)finishSelector - didFailSelector:(SEL)failSelector -{ - request = aRequest; - delegate = aDelegate; - didFinishSelector = finishSelector; - didFailSelector = failSelector; - - [request prepare]; - - responseData = [NSURLConnection sendSynchronousRequest:request - returningResponse:&response - error:&error]; - - if (response == nil || responseData == nil || error != nil) { - OAServiceTicket *ticket= [[OAServiceTicket alloc] initWithRequest:request - response:response - didSucceed:NO]; - [delegate performSelector:didFailSelector - withObject:ticket - withObject:error]; - } else { - OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request - response:response - didSucceed:[(NSHTTPURLResponse *)response statusCode] < 400]; - [delegate performSelector:didFinishSelector - withObject:ticket - withObject:responseData]; - } -} - -@end diff --git a/Classes/OAuth/OAHMAC_SHA1SignatureProvider.h b/Classes/OAuth/OAHMAC_SHA1SignatureProvider.h deleted file mode 100755 index d259c4ea..00000000 --- a/Classes/OAuth/OAHMAC_SHA1SignatureProvider.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// OAHMAC_SHA1SignatureProvider.h -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import -#import "OASignatureProviding.h" - - -@interface OAHMAC_SHA1SignatureProvider : NSObject -@end diff --git a/Classes/OAuth/OAHMAC_SHA1SignatureProvider.m b/Classes/OAuth/OAHMAC_SHA1SignatureProvider.m deleted file mode 100755 index 432baf7a..00000000 --- a/Classes/OAuth/OAHMAC_SHA1SignatureProvider.m +++ /dev/null @@ -1,58 +0,0 @@ -// -// OAHMAC_SHA1SignatureProvider.m -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "OAHMAC_SHA1SignatureProvider.h" -#import - -#include "Base64Transcoder.h" - -@implementation OAHMAC_SHA1SignatureProvider - -- (NSString *)name -{ - return @"HMAC-SHA1"; -} - -- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret -{ - NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding]; - NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding]; - unsigned char result[20]; - CCHmac(kCCHmacAlgSHA1, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], result); - - //Base64 Encoding - - char base64Result[32]; - size_t theResultLength = 32; - Base64EncodeData(result, 20, base64Result, &theResultLength); - NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength]; - - NSString *base64EncodedResult = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding]; - - return [base64EncodedResult autorelease]; -} - -@end diff --git a/Classes/OAuth/OAMutableURLRequest.h b/Classes/OAuth/OAMutableURLRequest.h deleted file mode 100755 index fdf0a1a8..00000000 --- a/Classes/OAuth/OAMutableURLRequest.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// OAMutableURLRequest.h -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import -#import "OAConsumer.h" -#import "OAToken.h" -#import "OAHMAC_SHA1SignatureProvider.h" -#import "OASignatureProviding.h" -#import "NSMutableURLRequest+Parameters.h" -#import "NSURL+Base.h" - - -@interface OAMutableURLRequest : NSMutableURLRequest { -@protected - OAConsumer *consumer; - OAToken *token; - NSString *realm; - NSString *signature; - id signatureProvider; - NSString *nonce; - NSString *timestamp; - NSMutableDictionary *extraOAuthParameters; -} -@property(readonly) NSString *signature; -@property(readonly) NSString *nonce; - -- (id)initWithURL:(NSURL *)aUrl - consumer:(OAConsumer *)aConsumer - token:(OAToken *)aToken - realm:(NSString *)aRealm -signatureProvider:(id)aProvider; - -- (id)initWithURL:(NSURL *)aUrl - consumer:(OAConsumer *)aConsumer - token:(OAToken *)aToken - realm:(NSString *)aRealm -signatureProvider:(id)aProvider - nonce:(NSString *)aNonce - timestamp:(NSString *)aTimestamp; - -- (void)prepare; - -- (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)parameterValue; - -@end diff --git a/Classes/OAuth/OAMutableURLRequest.m b/Classes/OAuth/OAMutableURLRequest.m deleted file mode 100755 index d32f759a..00000000 --- a/Classes/OAuth/OAMutableURLRequest.m +++ /dev/null @@ -1,231 +0,0 @@ -// -// OAMutableURLRequest.m -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "OAMutableURLRequest.h" - - -@interface OAMutableURLRequest (Private) -- (void)_generateTimestamp; -- (void)_generateNonce; -- (NSString *)_signatureBaseString; -@end - -@implementation OAMutableURLRequest -@synthesize signature, nonce; - -#pragma mark init - -- (id)initWithURL:(NSURL *)aUrl - consumer:(OAConsumer *)aConsumer - token:(OAToken *)aToken - realm:(NSString *)aRealm -signatureProvider:(id)aProvider -{ - if (self = [super initWithURL:aUrl - cachePolicy:NSURLRequestReloadIgnoringCacheData - timeoutInterval:10.0]) - { - consumer = [aConsumer retain]; - - // empty token for Unauthorized Request Token transaction - if (aToken == nil) - token = [[OAToken alloc] init]; - else - token = [aToken retain]; - - if (aRealm == nil) - realm = [[NSString alloc] initWithString:@""]; - else - realm = [aRealm retain]; - - // default to HMAC-SHA1 - if (aProvider == nil) - signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; - else - signatureProvider = [aProvider retain]; - - [self _generateTimestamp]; - [self _generateNonce]; - } - return self; -} - -// Setting a timestamp and nonce to known -// values can be helpful for testing -- (id)initWithURL:(NSURL *)aUrl - consumer:(OAConsumer *)aConsumer - token:(OAToken *)aToken - realm:(NSString *)aRealm -signatureProvider:(id)aProvider - nonce:(NSString *)aNonce - timestamp:(NSString *)aTimestamp -{ - if (self = [super initWithURL:aUrl - cachePolicy:NSURLRequestReloadIgnoringCacheData - timeoutInterval:10.0]) - { - consumer = [aConsumer retain]; - - // empty token for Unauthorized Request Token transaction - if (aToken == nil) - token = [[OAToken alloc] init]; - else - token = [aToken retain]; - - if (aRealm == nil) - realm = [[NSString alloc] initWithString:@""]; - else - realm = [aRealm retain]; - - // default to HMAC-SHA1 - if (aProvider == nil) - signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; - else - signatureProvider = [aProvider retain]; - - timestamp = [aTimestamp retain]; - nonce = [aNonce retain]; - } - return self; -} - -- (void)dealloc -{ - [consumer release]; - [token release]; - [realm release]; - [signatureProvider release]; - [timestamp release]; - [nonce release]; - [extraOAuthParameters release]; - [super dealloc]; -} - -#pragma mark - -#pragma mark Public - -- (void)setOAuthParameterName:(NSString*)parameterName withValue:(NSString*)parameterValue -{ - assert(parameterName && parameterValue); - - if (extraOAuthParameters == nil) { - extraOAuthParameters = [NSMutableDictionary new]; - } - - [extraOAuthParameters setObject:parameterValue forKey:parameterName]; -} - -- (void)prepare -{ - // sign - // Secrets must be urlencoded before concatenated with '&' - // TODO: if later RSA-SHA1 support is added then a little code redesign is needed - signature = [signatureProvider signClearText:[self _signatureBaseString] - withSecret:[NSString stringWithFormat:@"%@&%@", - [consumer.secret URLEncodedString], - [token.secret URLEncodedString]]]; - - // set OAuth headers - NSString *oauthToken; - if ([token.key isEqualToString:@""]) - oauthToken = @""; // not used on Request Token transactions - else - oauthToken = [NSString stringWithFormat:@"oauth_token=\"%@\", ", [token.key URLEncodedString]]; - - NSMutableString *extraParameters = [NSMutableString string]; - - // Adding the optional parameters in sorted order isn't required by the OAuth spec, but it makes it possible to hard-code expected values in the unit tests. - for(NSString *parameterName in [[extraOAuthParameters allKeys] sortedArrayUsingSelector:@selector(compare:)]) - { - [extraParameters appendFormat:@", %@=\"%@\"", - [parameterName URLEncodedString], - [[extraOAuthParameters objectForKey:parameterName] URLEncodedString]]; - } - - NSString *oauthHeader = [NSString stringWithFormat:@"OAuth realm=\"%@\", oauth_consumer_key=\"%@\", %@oauth_signature_method=\"%@\", oauth_signature=\"%@\", oauth_timestamp=\"%@\", oauth_nonce=\"%@\", oauth_version=\"1.0\"%@", - [realm URLEncodedString], - [consumer.key URLEncodedString], - oauthToken, - [[signatureProvider name] URLEncodedString], - [signature URLEncodedString], - timestamp, - nonce, - extraParameters]; - - [self setValue:oauthHeader forHTTPHeaderField:@"Authorization"]; -} - -#pragma mark - -#pragma mark Private - -- (void)_generateTimestamp -{ - timestamp = [[NSString stringWithFormat:@"%d", time(NULL)] retain]; -} - -- (void)_generateNonce -{ - CFUUIDRef theUUID = CFUUIDCreate(NULL); - CFStringRef string = CFUUIDCreateString(NULL, theUUID); - NSMakeCollectable(theUUID); - nonce = (NSString *)string; -} - -- (NSString *)_signatureBaseString -{ - // OAuth Spec, Section 9.1.1 "Normalize Request Parameters" - // build a sorted array of both request parameters and OAuth header parameters - NSMutableArray *parameterPairs = [NSMutableArray arrayWithCapacity:(6 + [[self parameters] count])]; // 6 being the number of OAuth params in the Signature Base String - - [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_consumer_key" value:consumer.key] URLEncodedNameValuePair]]; - [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_signature_method" value:[signatureProvider name]] URLEncodedNameValuePair]]; - [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_timestamp" value:timestamp] URLEncodedNameValuePair]]; - [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_nonce" value:nonce] URLEncodedNameValuePair]]; - [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_version" value:@"1.0"] URLEncodedNameValuePair]]; - - if (![token.key isEqualToString:@""]) { - [parameterPairs addObject:[[OARequestParameter requestParameterWithName:@"oauth_token" value:token.key] URLEncodedNameValuePair]]; - } - - for (OARequestParameter *param in [self parameters]) { - [parameterPairs addObject:[param URLEncodedNameValuePair]]; - } - - NSArray *sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)]; - NSString *normalizedRequestParameters = [sortedPairs componentsJoinedByString:@"&"]; - - // OAuth Spec, Section 9.1.2 "Concatenate Request Elements" - NSString *ret = [NSString stringWithFormat:@"%@&%@&%@", - [self HTTPMethod], - [[[self URL] URLStringWithoutQuery] URLEncodedString], - [normalizedRequestParameters URLEncodedString]]; - - //NSLog(@"ret %@", ret); - - return ret; -} - -@end diff --git a/Classes/OAuth/OAPlaintextSignatureProvider.h b/Classes/OAuth/OAPlaintextSignatureProvider.h deleted file mode 100755 index 96bb2f28..00000000 --- a/Classes/OAuth/OAPlaintextSignatureProvider.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// OAPlaintextSignatureProvider.h -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import -#import "OASignatureProviding.h" - -@interface OAPlaintextSignatureProvider : NSObject -@end diff --git a/Classes/OAuth/OAPlaintextSignatureProvider.m b/Classes/OAuth/OAPlaintextSignatureProvider.m deleted file mode 100755 index 6f0c1c3a..00000000 --- a/Classes/OAuth/OAPlaintextSignatureProvider.m +++ /dev/null @@ -1,43 +0,0 @@ -// -// OAPlaintextSignatureProvider.m -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "OAPlaintextSignatureProvider.h" -#import "NSString+URLEncoding.h" - - -@implementation OAPlaintextSignatureProvider - -- (NSString *)name -{ - return @"PLAINTEXT"; -} - -- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret -{ - return secret; -} - -@end diff --git a/Classes/OAuth/OAProblem.h b/Classes/OAuth/OAProblem.h deleted file mode 100755 index fe64c700..00000000 --- a/Classes/OAuth/OAProblem.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// OAProblem.h -// OAuthConsumer -// -// Created by Alberto García Hierro on 03/09/08. -// Copyright 2008 Alberto García Hierro. All rights reserved. -// bynotes.com - -#import - -enum { - kOAProblemSignatureMethodRejected = 0, - kOAProblemParameterAbsent, - kOAProblemVersionRejected, - kOAProblemConsumerKeyUnknown, - kOAProblemTokenRejected, - kOAProblemSignatureInvalid, - kOAProblemNonceUsed, - kOAProblemTimestampRefused, - kOAProblemTokenExpired, - kOAProblemTokenNotRenewable -}; - -@interface OAProblem : NSObject { - const NSString *problem; -} - -@property (readonly) const NSString *problem; - -- (id)initWithProblem:(const NSString *)aProblem; -- (id)initWithResponseBody:(const NSString *)response; - -- (BOOL)isEqualToProblem:(OAProblem *)aProblem; -- (BOOL)isEqualToString:(const NSString *)aProblem; -- (BOOL)isEqualTo:(id)aProblem; -- (int)code; - -+ (OAProblem *)problemWithResponseBody:(const NSString *)response; - -+ (const NSArray *)validProblems; - -+ (OAProblem *)SignatureMethodRejected; -+ (OAProblem *)ParameterAbsent; -+ (OAProblem *)VersionRejected; -+ (OAProblem *)ConsumerKeyUnknown; -+ (OAProblem *)TokenRejected; -+ (OAProblem *)SignatureInvalid; -+ (OAProblem *)NonceUsed; -+ (OAProblem *)TimestampRefused; -+ (OAProblem *)TokenExpired; -+ (OAProblem *)TokenNotRenewable; - -@end diff --git a/Classes/OAuth/OAProblem.m b/Classes/OAuth/OAProblem.m deleted file mode 100755 index 7a885a3c..00000000 --- a/Classes/OAuth/OAProblem.m +++ /dev/null @@ -1,165 +0,0 @@ -// -// OAProblem.m -// OAuthConsumer -// -// Created by Alberto García Hierro on 03/09/08. -// Copyright 2008 Alberto García Hierro. All rights reserved. -// bynotes.com - -#import "OAProblem.h" - -const NSString *signature_method_rejected = @"signature_method_rejected"; -const NSString *parameter_absent = @"parameter_absent"; -const NSString *version_rejected = @"version_rejected"; -const NSString *consumer_key_unknown = @"consumer_key_unknown"; -const NSString *token_rejected = @"token_rejected"; -const NSString *signature_invalid = @"signature_invalid"; -const NSString *nonce_used = @"nonce_used"; -const NSString *timestamp_refused = @"timestamp_refused"; -const NSString *token_expired = @"token_expired"; -const NSString *token_not_renewable = @"token_not_renewable"; - -@implementation OAProblem - -@synthesize problem; - -- (id)initWithPointer:(const NSString *) aPointer -{ - [super init]; - problem = aPointer; - return self; -} - -- (id)initWithProblem:(const NSString *) aProblem -{ - NSUInteger idx = [[OAProblem validProblems] indexOfObject:aProblem]; - if (idx == NSNotFound) { - return nil; - } - - return [self initWithPointer: [[OAProblem validProblems] objectAtIndex:idx]]; -} - -- (id)initWithResponseBody:(const NSString *) response -{ - NSArray *fields = [response componentsSeparatedByString:@"&"]; - for (NSString *field in fields) { - if ([field hasPrefix:@"oauth_problem="]) { - NSString *value = [[field componentsSeparatedByString:@"="] objectAtIndex:1]; - return [self initWithProblem:value]; - } - } - - return nil; -} - -+ (OAProblem *)problemWithResponseBody:(const NSString *) response -{ - return [[[OAProblem alloc] initWithResponseBody:response] autorelease]; -} - -+ (const NSArray *)validProblems -{ - static NSArray *array; - if (!array) { - array = [[NSArray alloc] initWithObjects:signature_method_rejected, - parameter_absent, - version_rejected, - consumer_key_unknown, - token_rejected, - signature_invalid, - nonce_used, - timestamp_refused, - token_expired, - token_not_renewable, - nil]; - } - - return array; -} - -- (BOOL)isEqualToProblem:(OAProblem *) aProblem -{ - return [problem isEqualToString:(NSString *)aProblem->problem]; -} - -- (BOOL)isEqualToString:(const NSString *) aProblem -{ - return [problem isEqualToString:(NSString *)aProblem]; -} - -- (BOOL)isEqualTo:(id) aProblem -{ - if ([aProblem isKindOfClass:[NSString class]]) { - return [self isEqualToString:aProblem]; - } - - if ([aProblem isKindOfClass:[OAProblem class]]) { - return [self isEqualToProblem:aProblem]; - } - - return NO; -} - -- (int)code { - return [[[self class] validProblems] indexOfObject:problem]; -} - -- (NSString *)description -{ - return [NSString stringWithFormat:@"OAuth Problem: %@", (NSString *)problem]; -} - -#pragma mark class_methods - -+ (OAProblem *)SignatureMethodRejected -{ - return [[[OAProblem alloc] initWithPointer:signature_method_rejected] autorelease]; -} - -+ (OAProblem *)ParameterAbsent -{ - return [[[OAProblem alloc] initWithPointer:parameter_absent] autorelease]; -} - -+ (OAProblem *)VersionRejected -{ - return [[[OAProblem alloc] initWithPointer:version_rejected] autorelease]; -} - -+ (OAProblem *)ConsumerKeyUnknown -{ - return [[[OAProblem alloc] initWithPointer:consumer_key_unknown] autorelease]; -} - -+ (OAProblem *)TokenRejected -{ - return [[[OAProblem alloc] initWithPointer:token_rejected] autorelease]; -} - -+ (OAProblem *)SignatureInvalid -{ - return [[[OAProblem alloc] initWithPointer:signature_invalid] autorelease]; -} - -+ (OAProblem *)NonceUsed -{ - return [[[OAProblem alloc] initWithPointer:nonce_used] autorelease]; -} - -+ (OAProblem *)TimestampRefused -{ - return [[[OAProblem alloc] initWithPointer:timestamp_refused] autorelease]; -} - -+ (OAProblem *)TokenExpired -{ - return [[[OAProblem alloc] initWithPointer:token_expired] autorelease]; -} - -+ (OAProblem *)TokenNotRenewable -{ - return [[[OAProblem alloc] initWithPointer:token_not_renewable] autorelease]; -} - -@end diff --git a/Classes/OAuth/OARequestParameter.h b/Classes/OAuth/OARequestParameter.h deleted file mode 100755 index 03eee3e0..00000000 --- a/Classes/OAuth/OARequestParameter.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// OARequestParameter.h -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import -#import "NSString+URLEncoding.h" - - -@interface OARequestParameter : NSObject { -@protected - NSString *name; - NSString *value; -} -@property(retain) NSString *name; -@property(retain) NSString *value; - -+ (id)requestParameterWithName:(NSString *)aName value:(NSString *)aValue; -- (id)initWithName:(NSString *)aName value:(NSString *)aValue; -- (NSString *)URLEncodedName; -- (NSString *)URLEncodedValue; -- (NSString *)URLEncodedNameValuePair; - -@end diff --git a/Classes/OAuth/OARequestParameter.m b/Classes/OAuth/OARequestParameter.m deleted file mode 100755 index 59b6a8a6..00000000 --- a/Classes/OAuth/OARequestParameter.m +++ /dev/null @@ -1,70 +0,0 @@ -// -// OARequestParameter.m -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "OARequestParameter.h" - - -@implementation OARequestParameter -@synthesize name, value; - -+ (id)requestParameterWithName:(NSString *)aName value:(NSString *)aValue -{ - return [[[OARequestParameter alloc] initWithName:aName value:aValue] autorelease]; -} - -- (id)initWithName:(NSString *)aName value:(NSString *)aValue -{ - if (self = [super init]) - { - self.name = aName; - self.value = aValue; - } - return self; -} - -- (void)dealloc -{ - [name release]; - [value release]; - [super dealloc]; -} - -- (NSString *)URLEncodedName -{ - return [self.name URLEncodedString]; -} - -- (NSString *)URLEncodedValue -{ - return [self.value URLEncodedString]; -} - -- (NSString *)URLEncodedNameValuePair -{ - return [NSString stringWithFormat:@"%@=%@", [self URLEncodedName], [self URLEncodedValue]]; -} - -@end diff --git a/Classes/OAuth/OAServiceTicket.h b/Classes/OAuth/OAServiceTicket.h deleted file mode 100755 index 9a8eb348..00000000 --- a/Classes/OAuth/OAServiceTicket.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// OAServiceTicket.h -// OAuthConsumer -// -// Created by Jon Crosby on 11/5/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import -#import "OAMutableURLRequest.h" - - -@interface OAServiceTicket : NSObject { -@private - OAMutableURLRequest *request; - NSHTTPURLResponse *response; - NSData *data; - BOOL didSucceed; -} -@property(readonly) OAMutableURLRequest *request; -@property(readonly) NSHTTPURLResponse *response; -@property(readonly) NSData *data; -@property(readonly) BOOL didSucceed; -@property(readonly) NSString *body; - -- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse didSucceed:(BOOL)success; -- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success; - -@end diff --git a/Classes/OAuth/OAServiceTicket.m b/Classes/OAuth/OAServiceTicket.m deleted file mode 100755 index fb6e3b7c..00000000 --- a/Classes/OAuth/OAServiceTicket.m +++ /dev/null @@ -1,56 +0,0 @@ -// -// OAServiceTicket.m -// OAuthConsumer -// -// Created by Jon Crosby on 11/5/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "OAServiceTicket.h" - - -@implementation OAServiceTicket -@synthesize request, response, data, didSucceed; - -- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse didSucceed:(BOOL)success -{ - return [self initWithRequest:aRequest response:aResponse data:nil didSucceed:success]; -} - -- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSHTTPURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success { - [super init]; - request = aRequest; - response = aResponse; - data = aData; - didSucceed = success; - return self; -} - -- (NSString *)body -{ - if (!data) { - return nil; - } - - return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; -} - -@end diff --git a/Classes/OAuth/OASignatureProviding.h b/Classes/OAuth/OASignatureProviding.h deleted file mode 100755 index 0c7e4f8c..00000000 --- a/Classes/OAuth/OASignatureProviding.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// OASignatureProviding.h -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import - - -@protocol OASignatureProviding - -- (NSString *)name; -- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret; - -@end diff --git a/Classes/OAuth/OAToken.h b/Classes/OAuth/OAToken.h deleted file mode 100755 index 8dd331e1..00000000 --- a/Classes/OAuth/OAToken.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// OAToken.h -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import - -@interface OAToken : NSObject { -@protected - NSString *key; - NSString *secret; -} -@property(retain) NSString *key; -@property(retain) NSString *secret; - -- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; -- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; -- (id)initWithHTTPResponseBody:(NSString *)body; -- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; - -@end diff --git a/Classes/OAuth/OAToken.m b/Classes/OAuth/OAToken.m deleted file mode 100755 index d4f24911..00000000 --- a/Classes/OAuth/OAToken.m +++ /dev/null @@ -1,105 +0,0 @@ -// -// OAToken.m -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#import "OAToken.h" - - -@implementation OAToken - -@synthesize key, secret; - -#pragma mark init - -- (id)init -{ - if (self = [super init]) - { - self.key = @""; - self.secret = @""; - } - return self; -} - -- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret -{ - if (self = [super init]) - { - self.key = aKey; - self.secret = aSecret; - } - return self; -} - -- (id)initWithHTTPResponseBody:(NSString *)body -{ - if (self = [super init]) - { - NSArray *pairs = [body componentsSeparatedByString:@"&"]; - - for (NSString *pair in pairs) { - NSArray *elements = [pair componentsSeparatedByString:@"="]; - if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token"]) { - self.key = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_secret"]) { - self.secret = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - } - } - } - return self; -} - -- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix -{ - if (self = [super init]) - { - NSString *theKey = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@"OAUTH_%@_%@_KEY", prefix, provider]]; - NSString *theSecret = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@"OAUTH_%@_%@_SECRET", prefix, provider]]; - if (theKey == NULL || theSecret == NULL) - return(nil); - self.key = theKey; - self.secret = theSecret; - } - return self; -} - -- (void)dealloc -{ - [key release]; - [secret release]; - [super dealloc]; -} - -#pragma mark - - -- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix -{ - [[NSUserDefaults standardUserDefaults] setObject:self.key forKey:[NSString stringWithFormat:@"OAUTH_%@_%@_KEY", prefix, provider]]; - [[NSUserDefaults standardUserDefaults] setObject:self.secret forKey:[NSString stringWithFormat:@"OAUTH_%@_%@_SECRET", prefix, provider]]; - [[NSUserDefaults standardUserDefaults] synchronize]; - return(0); -} - -@end diff --git a/Classes/OAuth/OAuthConsumer.h b/Classes/OAuth/OAuthConsumer.h deleted file mode 100755 index 1ac26b20..00000000 --- a/Classes/OAuth/OAuthConsumer.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// OAuthConsumer.h -// OAuthConsumer -// -// Created by Jon Crosby on 10/19/07. -// Copyright 2007 Kaboomerang LLC. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "OAToken.h" -#import "OAConsumer.h" -#import "OAMutableURLRequest.h" -#import "NSString+URLEncoding.h" -#import "NSMutableURLRequest+Parameters.h" -#import "NSURL+Base.h" -#import "OASignatureProviding.h" -#import "OAHMAC_SHA1SignatureProvider.h" -#import "OAPlaintextSignatureProvider.h" -#import "OARequestParameter.h" -#import "OAServiceTicket.h" -#import "OADataFetcher.h" -#import "OAAsynchronousDataFetcher.h" \ No newline at end of file diff --git a/ShareKit.bundle/de.lproj/Localizable.strings b/ShareKit.bundle/de.lproj/Localizable.strings deleted file mode 100644 index 37ce9c369c5937ef952d514a10a5a547072b0db1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8220 zcmchc$!=Ul6ozZfQ(PjkLl#J^f{<{MPGph6iXBk0YtOB;+s5sT56YGe&%i1I{;z%? zSKWK7Jwy?*oOD;6I^%zaD*yY>ois_uX_{tfp6;YB{iNUi+K=fgt-MIfw4ct>LbS*F zRA|RLKCvmvrGDO}6P??uPV{%qwc`^HMLE~ciOzKCoAh&a#(Rg796LU9U(}0qF8vqj zO;4}i^lhdcvsg3Z>1^P7y0#iaNE?$9i5*^PNDoG9q0$C=NEfN zm-6q6?`ifJo-1d5k=4gJww%ICA!9rH(H;tfc+ECj>usGmRJ;qvvJ##mw&1AHY-RtT z|9<*2YaCLaiWd88j$WIkk4?(Lwa^8(t0P}WClFF2_L1bF3t3X|IuWWtSdkkmSVQa! z-*wpuO7VGZ(RzA)xn9$6We#t30%X-E9%v29rOx3=`xg3z^y##Ea+xC$tye;c^QO}| zQ`XYRqSN%DvII1oW=VZJOo;}2>FX8r=XodenhMEe=iv(7o(ebQNYU?9+_9Uyq2d%9 z;Wd;@Y?jisK2vM(Eaw6UTZpE_YPfEFCz5z3+d+SL@1f2eDe`qCc`Ta4%(KwdYv$$^ z(_#OHbcpH^+$Wg}nQ^Eeq7oD}547)8tFP9sQ!T&`$D$o;<64Oqj74G+vO=3*vz0qp zr#*d+eRQD@kVkk2>@6}CcD+c?B`;|Eyk2L|+52E=NNp?oe1qn87F+keJiLY-XP0sV zP4tIOo;Xo%%yZ@}^!Z$C%bty76i5u6)+%J!?oK&OUQ;)r!!Mv0Uf}gi`=BR$!1}wq zj%Ew_%{t-V`=Z`gMwru7lm~eQzT}DZMH1inx8En9>oj%kg& zyN)cRp=&eiRI6H&Q5CWrv7x4%yNQNi*fQz$Lyd-#r;5&jINQpCLToD4Zd?AO663Wx zbJw%w{oPgt#Pf7_<`udaTH!-iQ|c++Azw+?vqt4m-dIy3;&u94=cxz8jw$fHIP?Ep z-$R2}+K*}sU07#7qDkO)l@IsDlZm75FJqnTaS)ANj-&neQr@9|9qV6^1BRVzWHmX$ zMB0xXntJYpQ*_1feC@5si{tbu^RPD}OS;t3)Vtt>%s|!~=|H6+$LO%=wUa-AQ_~n7 zwbx7DPb!N(WP8!NZ`a*x&^Ocy`pB3K@n@o>50W>;#8bch)G0#!dA;`0!+dg?agJ@} z&cNxYufw^%;9~otg5sI8JP$C{IF6;xut#^tclea=?!{~RwwZB(j+~^rku78^c0dm@ zog=mG4>F%F)pOHT6`QybSzGI>=$UC)wYzjrl3jJ8(l3PsPcCQ_*n%7Ra+?0S(9qVA zdvCNd^b~$T8rB-&)&P8w@ttfZC%{NxIxxPSvB;f(n@Xuy_r%ka!KThe)rY$)Y<Ccx>Qd=aVqqtemcfO&HHi02jh8gGh4MIt+;j6b9d2sOLn43nF>4I0;meZ)1RaJ zmSlsq59wQRBvhH=@h`zTZBQ9o(2aK|a^1Y0kNN`YZmO zotEa;$ErCm?Hej z#v2Y>c^CA=AGlo?3g~t2tb6IM zIQH+9+@hF>jx@dS>Aa$e`SNACKx_lm1lddqb@ta)(K&<`tvAB4VQz&~kpByxeV=jnSY@538pn)kjLuAf{7vY~SUbeU>a6T*9oo2d+&)Kx8|O+W)8U^@x8FnK3#TK>A-7>bGXgnL9R`7ywKpWVtc4xvW%&UH}Q4p$V=^3&b8Lx Y3PB^-;0+>r=aAZOIZN%A+YwU#1L}uKg#Z8m diff --git a/ShareKit.bundle/en.lproj/Localizable.strings b/ShareKit.bundle/en.lproj/Localizable.strings deleted file mode 100644 index ebc4261698c2ce0d9f33e88be430d224ea1d935c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7834 zcmd5>U2hvV5ae@y#l=A13L^#jl%PNjS1AHGjZi5F@~AkfEmU8TWT)wmZ#%>BhD+Y* zB%kEC5Nt`j<#Kj+xVxnO{pTd~!Yqu!Buv9esKQV9%g0`XCm4Af)?pl0VGh|DJ|)@u z6V2#Da*fyLu)w^JZbtoyX1s*t6t4y5RN=euvzycOOta1*KMxyNFb_8wvicLv7=&wJ zTV=9-Oj55S?r}JcuVimIZYV}r{}MXAAJ4H)8nxA@zRaWppju~N$OGRbjNl07h&en=~(5lNiE?_?i+>d}|u zwla6oZH!iK?Eu#2PtuGzP*hlDQQH@sRe!3P#jGN%DR*&(D`E$)y=Az}|7Cl~KXp^B9W^FQ>Ug6G~N6Tr^+wgn1 zsOj5BR_Jm`)0f-f_g+HKEGw<=fU$zT3uLZo-H zHRiGEvj)&(6MR;#VD6eCqU3Ul*uL`ePL8fZc4KAP#5FFlCavZQQ)Img^^XXC2tS5r zc)z@>`t+u(BQot!RypD#vrZklZ?&GRYxcz${T8dU&*Qr#rSUzyaRV!7_)kAo(N0+} zZqG21$4fqB$3_NNo;Oc>?>vllV^R+hF{EFj9YmAkeePnlue|AJUT2TR8pG;JKdTQW zhq%@f-+c$`ZSOW)Q5oLluXXgW^#Y1b$}aRiD<$K^nDD!5+$p~Gfty*1IvAr>WIT5r zZJ_)VpX5J}`!Uw`R@0^mIflr^Kw7{KhNxMcQml=0#=#+2Jd0iJs@SEh2glTG9Fez5 z&3QCfpXyytKicyFOyWtycbUi3X*dUwvE;z_@F2O#-OjF_f7-|NFxg~PRaIpibBp)- zW%ML>zfM)$A#3=1H|IRh{y&JszJ2h};$!W<`}*S8Yq#&YC1SjYJBeAZnZZpg@>VtT zm|3&CZsRl8W+a&L)B{(sf|1E~1EIV~MwfXybr*-~Y4c*41=!nM;WYt5<}tqO#P%zm z@EJ39h2EQaTh%ooZT9AI)@ZY$9nt|z!u%@@P>h1+~H{3G#lnOv2Kumg@)Of`2}4uwG}YUy*C#@CL3YN_F0{TOU+oyW4A)uQD_oUl z;_^89B ze4EwGEBkp^ykd^ePa56>I*VSz&MqUT$6eAJnsMe zW~4cTaxW;$o#In|QeZt*r6N+#k%!XX=Fxf%B)(5zFi)ka>X@Bm%Ow1b9bz}Gx}90X zE+*$lv*#aTMOnzYo{%@+hPBDG`RQ?)r#z;cM0%h6>LC*4jq5JCt`?TjKYWjE(@2E8 zH#JMxm6K_{2P*Gj_mOS0e1Asr?oqcj56AkpHIjF{R5KH{Nwj(5aanE^Ta`W65H From a41fde8c221c79d09df2b96234a3626585d3bde5 Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Thu, 26 Aug 2010 15:25:35 -0700 Subject: [PATCH 39/50] - Fixed: Offline sharing of images and files --- Classes/ShareKit/Core/SHK.h | 3 ++- Classes/ShareKit/Core/SHK.m | 21 ++++++++++++------- Classes/ShareKit/Core/SHKOfflineSharer.h | 2 +- Classes/ShareKit/Core/SHKOfflineSharer.m | 11 ++++++---- .../Sharers/Services/Twitter/SHKTwitter.m | 1 - 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index f3cfbef6..8603c5f9 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -104,11 +104,12 @@ #pragma mark - #pragma mark Offline Support -+ (void)flushOfflineQueue; ++ (NSString *)offlineQueuePath; + (NSString *)offlineQueueListPath; + (NSMutableArray *)getOfflineQueueList; + (void)saveOfflineQueueList:(NSMutableArray *)queueList; + (BOOL)addToOfflineQueue:(SHKItem *)item forSharer:(NSString *)sharerId; ++ (void)flushOfflineQueue; #pragma mark - diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m index 2614ff81..187d0bfb 100644 --- a/Classes/ShareKit/Core/SHK.m +++ b/Classes/ShareKit/Core/SHK.m @@ -418,19 +418,23 @@ + (NSDictionary *)sharersDictionary #pragma mark - #pragma mark Offline Support -+ (NSString *)offlineQueueListPath ++ (NSString *)offlineQueuePath { NSFileManager *fileManager = [NSFileManager defaultManager]; NSArray *paths = NSSearchPathForDirectoriesInDomains( NSCachesDirectory, NSUserDomainMask, YES); NSString *cache = [paths objectAtIndex:0]; NSString *SHKPath = [cache stringByAppendingPathComponent:@"SHK"]; - NSString *listPath = [SHKPath stringByAppendingPathComponent:@"SHKOfflineQueue.plist"]; // Check if the path exists, otherwise create it if (![fileManager fileExistsAtPath:SHKPath]) [fileManager createDirectoryAtPath:SHKPath withIntermediateDirectories:YES attributes:nil error:nil]; - return listPath; + return SHKPath; +} + ++ (NSString *)offlineQueueListPath +{ + return [[self offlineQueuePath] stringByAppendingPathComponent:@"SHKOfflineQueue.plist"]; } + (NSMutableArray *)getOfflineQueueList @@ -451,11 +455,11 @@ + (BOOL)addToOfflineQueue:(SHKItem *)item forSharer:(NSString *)sharerId // store image in cache if (item.shareType == SHKShareTypeImage && item.image) - [UIImageJPEGRepresentation(item.image, 100) writeToFile:[[self offlineQueueListPath] stringByAppendingPathComponent:uid] atomically:YES]; + [UIImageJPEGRepresentation(item.image, 1) writeToFile:[[self offlineQueuePath] stringByAppendingPathComponent:uid] atomically:YES]; // store file in cache else if (item.shareType == SHKShareTypeFile) - [item.data writeToFile:[[self offlineQueueListPath] stringByAppendingPathComponent:uid] atomically:YES]; + [item.data writeToFile:[[self offlineQueuePath] stringByAppendingPathComponent:uid] atomically:YES]; // Open queue list NSMutableArray *queueList = [self getOfflineQueueList]; @@ -496,19 +500,21 @@ + (void)flushOfflineQueue helper.offlineQueue = [[NSOperationQueue alloc] init]; SHKItem *item; - NSString *sharerId; + NSString *sharerId, *uid; for (NSDictionary *entry in queueList) { item = [SHKItem itemFromDictionary:[entry objectForKey:@"item"]]; sharerId = [entry objectForKey:@"sharer"]; + uid = [entry objectForKey:@"uid"]; if (item != nil && sharerId != nil) - [helper.offlineQueue addOperation:[[[SHKOfflineSharer alloc] initWithItem:item forSharer:sharerId] autorelease]]; + [helper.offlineQueue addOperation:[[[SHKOfflineSharer alloc] initWithItem:item forSharer:sharerId uid:uid] autorelease]]; } // Remove offline queue - TODO: only do this if everything was successful? [[NSFileManager defaultManager] removeItemAtPath:[self offlineQueueListPath] error:nil]; + } } @@ -529,6 +535,7 @@ + (NSError *)error:(NSString *)description, ... + (BOOL)connected { + //return NO; // force for offline testing Reachability *hostReach = [Reachability reachabilityForInternetConnection]; NetworkStatus netStatus = [hostReach currentReachabilityStatus]; return !(netStatus == NotReachable); diff --git a/Classes/ShareKit/Core/SHKOfflineSharer.h b/Classes/ShareKit/Core/SHKOfflineSharer.h index 1312969e..c2b74a14 100644 --- a/Classes/ShareKit/Core/SHKOfflineSharer.h +++ b/Classes/ShareKit/Core/SHKOfflineSharer.h @@ -46,7 +46,7 @@ @property (nonatomic, retain) NSThread *runLoopThread; @property (nonatomic, retain) SHKSharer *sharer; -- (id)initWithItem:(SHKItem *)i forSharer:(NSString *)s; +- (id)initWithItem:(SHKItem *)i forSharer:(NSString *)s uid:(NSString *)u; - (void)share; - (BOOL)shouldRun; diff --git a/Classes/ShareKit/Core/SHKOfflineSharer.m b/Classes/ShareKit/Core/SHKOfflineSharer.m index 5273416d..0c9ce9d8 100644 --- a/Classes/ShareKit/Core/SHKOfflineSharer.m +++ b/Classes/ShareKit/Core/SHKOfflineSharer.m @@ -45,12 +45,13 @@ - (void)dealloc [super dealloc]; } -- (id)initWithItem:(SHKItem *)i forSharer:(NSString *)s +- (id)initWithItem:(SHKItem *)i forSharer:(NSString *)s uid:(NSString *)u { if (self = [super init]) { self.item = i; self.sharerId = s; + self.uid = u; } return self; } @@ -91,17 +92,19 @@ - (void)share NSString *path; if (item.shareType == SHKShareTypeImage) { - path = [[SHK offlineQueueListPath] stringByAppendingPathComponent:uid]; + path = [[SHK offlineQueuePath] stringByAppendingPathComponent:uid]; sharer.item.image = [UIImage imageWithContentsOfFile:path]; [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + } // reload file from disk and remove the file else if (item.shareType == SHKShareTypeFile) { path = [[SHK offlineQueueListPath] stringByAppendingPathComponent:uid]; - sharer.item.data = [NSData dataWithContentsOfFile:[[SHK offlineQueueListPath] stringByAppendingPathComponent:uid]]; - [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + sharer.item.data = [NSData dataWithContentsOfFile:[[SHK offlineQueuePath] stringByAppendingPathComponent:uid]]; + [[NSFileManager defaultManager] removeItemAtPath:path error:nil]; + } [sharer tryToSend]; diff --git a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m index 484e1da9..c49b4a83 100644 --- a/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m +++ b/Classes/ShareKit/Sharers/Services/Twitter/SHKTwitter.m @@ -378,7 +378,6 @@ - (void)sendStatusTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)d // this is the error message for revoked access if ([errorMessage isEqualToString:@"Invalid / used nonce"]) { - NSError *error = [NSError errorWithDomain:@"Twitter" code:1 userInfo:[NSDictionary dictionaryWithObject:@"Invalid Login" forKey:NSLocalizedDescriptionKey]]; [self sendDidFailShouldRelogin]; } else From bc2604329b11c27d6179b2423ef77a0ca3550edb Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Fri, 27 Aug 2010 11:09:01 -0700 Subject: [PATCH 40/50] Missed SHKSwizzle header update --- Classes/ShareKit/Core/SHK.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Core/SHK.h b/Classes/ShareKit/Core/SHK.h index 8603c5f9..73a9aba1 100644 --- a/Classes/ShareKit/Core/SHK.h +++ b/Classes/ShareKit/Core/SHK.h @@ -127,4 +127,4 @@ NSString * SHKStringOrBlank(NSString * value); NSString * SHKEncode(NSString * value); NSString * SHKEncodeURL(NSURL * value); NSString* SHKLocalizedString(NSString* key, ...); -void SHKSwizzle(Class c, SEL orig, SEL new); +void SHKSwizzle(Class c, SEL orig, SEL newClassName); From 7f35b4ee53a762fd7a135577379dfb9af47af2de Mon Sep 17 00:00:00 2001 From: Nate Weiner Date: Mon, 30 Aug 2010 14:46:34 -0700 Subject: [PATCH 41/50] Reverted objc-class import line --- Classes/ShareKit/Core/SHK.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/Core/SHK.m b/Classes/ShareKit/Core/SHK.m index 187d0bfb..057de631 100644 --- a/Classes/ShareKit/Core/SHK.m +++ b/Classes/ShareKit/Core/SHK.m @@ -32,7 +32,7 @@ #import "SHKOfflineSharer.h" #import "SFHFKeychainUtils.h" #import "Reachability.h" -#import +#import #import From 37a40159cb54c3425271beeae67d7f4554e67cac Mon Sep 17 00:00:00 2001 From: pippolino Date: Sun, 14 Nov 2010 13:50:00 +0100 Subject: [PATCH 42/50] Add Licorize Service --- Classes/ShareKit/Core/SHKSharers.plist | 1 + .../Sharers/Services/Licorize/SHKLicorize.h | 25 ++ .../Sharers/Services/Licorize/SHKLicorize.m | 294 ++++++++++++++++++ ShareKit.xcodeproj/project.pbxproj | 17 +- 4 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.h create mode 100644 Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m diff --git a/Classes/ShareKit/Core/SHKSharers.plist b/Classes/ShareKit/Core/SHKSharers.plist index f4b31984..8e2b86ff 100644 --- a/Classes/ShareKit/Core/SHKSharers.plist +++ b/Classes/ShareKit/Core/SHKSharers.plist @@ -19,6 +19,7 @@ SHKReadItLater SHKInstapaper SHKTumblr + SHKLicorize
diff --git a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.h b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.h new file mode 100644 index 00000000..eabb0e65 --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.h @@ -0,0 +1,25 @@ +// +// SHKLicorize.h +// ShareKit +// +// Created by Federico Soldani on 11/13/10. + +#import +#import "SHKOAuthSharer.h" + +@interface SHKLicorize : SHKOAuthSharer { + BOOL xAuth; +} + +@property BOOL xAuth; + +#pragma mark - +#pragma mark Share API Methods + +- (void)remindMeLater; +- (void)saveStrip; + +- (void)sendTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data; +- (void)sendTicket:(OAServiceTicket *)ticket didFailWithError:(NSError *)error; + +@end diff --git a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m new file mode 100644 index 00000000..63a7044e --- /dev/null +++ b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m @@ -0,0 +1,294 @@ +// +// SHKLicorize.h +// ShareKit +// +// Created by Federico Soldani on 11/13/10. + +#import "SHKLicorize.h" + +@interface SHKLicorize () +NSString * UrlOrBlank(NSURL * value); +BOOL SendDidSuccess(NSData * data); +@end + +@implementation SHKLicorize + +@synthesize xAuth; + +#pragma mark - +#pragma mark Configuration : Service Defination + +// Enter the name of the service ++ (NSString *)sharerTitle { + return @"Licorize"; +} + ++ (BOOL)canShareURL { + return YES; +} + ++ (BOOL)canShareText { + return YES; +} + +#pragma mark - +#pragma mark Configuration : Dynamic Enable + +// Subclass if you need to dynamically enable/disable the service. (For example if it only works with specific hardware) ++ (BOOL)canShare { + return YES; +} + +#pragma mark - +#pragma mark Authorization + +- (BOOL)isAuthorized { + return [self restoreAccessToken]; +} + +- (void)promptAuthorization { + if (xAuth) { + [super authorizationFormShow]; // xAuth process + } else { + [super promptAuthorization]; // OAuth process + } +} + + +#pragma mark xAuth + ++ (NSString *)authorizationFormCaption { + return SHKLocalizedString(@"Create a free account at %@", @"Licorize.com"); +} + +- (void)authorizationFormValidate:(SHKFormController *)form { + self.pendingForm = form; + [self tokenAccess]; +} + +#pragma mark - +#pragma mark Authentication + +- (id)init { + if (self = [super init]) { + // OAUTH + self.consumerKey = SHKLicorizeConsumerKey; + self.secretKey = SHKLicorizeSecret; + self.authorizeCallbackURL = [NSURL URLWithString:SHKLicorizeCallbackUrl]; + + // XAUTH + self.xAuth = SHKLicorizeUseXAuth ? YES : NO; + + + // -- // + + + // You do not need to edit these, they are the same for everyone + self.requestURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/authorize"]; + self.authorizeURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/request_token"]; + self.accessURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/access_token"]; + + self.signatureProvider = [[[OAHMAC_SHA1SignatureProvider alloc] init] autorelease]; + } + return self; +} + +- (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest { + if (xAuth) { + NSDictionary *formValues = [pendingForm formValues]; + + OARequestParameter *username = [[[OARequestParameter alloc] initWithName:@"x_auth_username" + value:[formValues objectForKey:@"username"]] autorelease]; + + OARequestParameter *password = [[[OARequestParameter alloc] initWithName:@"x_auth_password" + value:[formValues objectForKey:@"password"]] autorelease]; + + OARequestParameter *mode = [[[OARequestParameter alloc] initWithName:@"x_auth_mode" + value:@"client_auth"] autorelease]; + + [oRequest setParameters:[NSArray arrayWithObjects:username, password, mode, nil]]; + } +} + +// Validate the user input on the share form +- (void)shareFormValidate:(SHKCustomFormController *)form { + /* + + Services should subclass this if they need to validate any data before sending. + You can get a dictionary of the field values from [form formValues] + + -- + + You should perform one of the following actions: + + 1. Save the form - If everything is correct call [form saveForm] + + 2. Display an error - If the user input was incorrect, display an error to the user and tell them what to do to fix it + + + */ + + // default does no checking and proceeds to share + [form saveForm]; +} + + + +#pragma mark - +#pragma mark Implementation + +// Send the share item to the server +- (BOOL)send { + if (![self validateItem]) + return NO; + + if ( (item.shareType == SHKShareTypeURL) || (item.shareType == SHKShareTypeText)) { + if ( item.shareType == SHKShareTypeURL ) { + [self remindMeLater]; + } else { + [self saveStrip]; + } + + // Notify delegate + [self sendDidStart]; + + return YES; + } else { + return NO; + } +} + +- (void)remindMeLater { + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.licorize.com/1/strips/remindMeLater.json"] + consumer:consumer + token:accessToken + realm:nil + signatureProvider:nil]; + + [oRequest setHTTPMethod:@"POST"]; + + OARequestParameter *urlParam = [[OARequestParameter alloc] initWithName:@"url" + value:UrlOrBlank(item.URL)]; + OARequestParameter *titleParam = [[OARequestParameter alloc] initWithName:@"title" + value:SHKStringOrBlank(item.title)]; + + NSArray *params = [NSArray arrayWithObjects:urlParam, titleParam, nil]; + [oRequest setParameters:params]; + [urlParam release]; + [titleParam release]; + + OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest + delegate:self + didFinishSelector:@selector(sendTicket:didFinishWithData:) + didFailSelector:@selector(sendTicket:didFailWithError:)]; + + [fetcher start]; + [oRequest release]; +} + +- (void)saveStrip { + OAMutableURLRequest *oRequest = [[OAMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.licorize.com/1/strips/update.json"] + consumer:consumer + token:accessToken + realm:nil + signatureProvider:nil]; + + [oRequest setHTTPMethod:@"POST"]; + + OARequestParameter *urlParam = [[OARequestParameter alloc] initWithName:@"url" + value:UrlOrBlank(item.URL)]; + OARequestParameter *titleParam = [[OARequestParameter alloc] initWithName:@"title" + value:SHKStringOrBlank(item.title)]; + OARequestParameter *textParam = [[OARequestParameter alloc] initWithName:@"notes" + value:SHKStringOrBlank(item.text)]; + OARequestParameter *typeParam = [[OARequestParameter alloc] initWithName:@"type" + value:@"NOTE"]; + OARequestParameter *tagsParam = [[OARequestParameter alloc] initWithName:@"tags" + value:SHKStringOrBlank(item.tags)]; + + NSArray *params = [NSArray arrayWithObjects:urlParam, titleParam, textParam, typeParam, tagsParam, nil]; + [oRequest setParameters:params]; + [urlParam release]; + [titleParam release]; + [textParam release]; + [typeParam release]; + [tagsParam release]; + + OAAsynchronousDataFetcher *fetcher = [OAAsynchronousDataFetcher asynchronousFetcherWithRequest:oRequest + delegate:self + didFinishSelector:@selector(sendTicket:didFinishWithData:) + didFailSelector:@selector(sendTicket:didFailWithError:)]; + + [fetcher start]; + [oRequest release]; +} + +- (void)sendTicket:(OAServiceTicket *)ticket didFinishWithData:(NSData *)data { + if (ticket.didSucceed && SendDidSuccess(data)) { + [self sendDidFinish]; + } else { + NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + + if (SHKDebugShowLogs) + SHKLog(@"Licorize RemindMeLater Error: %@", string); + + // in case our makeshift parsing does not yield an error message + NSString *errorMessage = @"Unknown Error"; + + NSScanner *scanner = [NSScanner scannerWithString:string]; + + // skip until error message + [scanner scanUpToString:@"\"message\":\"" intoString:nil]; + + + if ([scanner scanString:@"\"message\":\"" intoString:nil]) { + // get the message until the closing double quotes + [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\""] intoString:&errorMessage]; + } + + + // this is the error message for revoked access + if ([errorMessage isEqualToString:@"Invalid / used nonce"]) { + [self sendDidFailShouldRelogin]; + } else { + NSError *error = [NSError errorWithDomain:@"Licorize" code:2 userInfo:[NSDictionary dictionaryWithObject:errorMessage forKey:NSLocalizedDescriptionKey]]; + [self sendDidFailWithError:error]; + } + } +} + +- (void)sendTicket:(OAServiceTicket *)ticket didFailWithError:(NSError *)error { + [self sendDidFailWithError:error]; +} + +#pragma mark - +#pragma mark Utilities + +NSString * UrlOrBlank(NSURL * value) { + return value == nil ? @"" : [value absoluteString]; +} + +BOOL SendDidSuccess(NSData * data) { + NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + + NSScanner *scanner = [NSScanner scannerWithString:string]; + + NSString *success = @"true"; + + // skip until success message + [scanner scanUpToString:@"\"ok\":" intoString:nil]; + + if ([scanner scanString:@"\"ok\":" intoString:nil]) { + // get the message until the closing double quotes + [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@","] intoString:&success]; + } + + if([success isEqualToString:@"true"]) { + return YES; + } else { + return NO; + } + +} + +@end diff --git a/ShareKit.xcodeproj/project.pbxproj b/ShareKit.xcodeproj/project.pbxproj index 97079860..8afa3bd1 100755 --- a/ShareKit.xcodeproj/project.pbxproj +++ b/ShareKit.xcodeproj/project.pbxproj @@ -88,6 +88,7 @@ 43D1DEF011D5CDD200550D75 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43D1DEEF11D5CDD200550D75 /* SystemConfiguration.framework */; }; 43EF406E11D3FFF800B1F700 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43EF406D11D3FFF800B1F700 /* Security.framework */; }; 43FF9C7412270E9F00ADE53C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 43FF9C7212270E9F00ADE53C /* Localizable.strings */; }; + 7A6206941290046B00C638F3 /* SHKLicorize.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A6206931290046B00C638F3 /* SHKLicorize.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -245,6 +246,8 @@ 43EF406D11D3FFF800B1F700 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 43FF9C7312270E9F00ADE53C /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = Classes/ShareKit/Localization/en.lproj/Localizable.strings; sourceTree = SOURCE_ROOT; }; 43FF9C7512270EB900ADE53C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Classes/ShareKit/Localization/de.lproj/Localizable.strings; sourceTree = SOURCE_ROOT; }; + 7A6206921290046B00C638F3 /* SHKLicorize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHKLicorize.h; sourceTree = ""; }; + 7A6206931290046B00C638F3 /* SHKLicorize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHKLicorize.m; sourceTree = ""; }; 8D1107310486CEB800E47090 /* ShareKit-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ShareKit-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -560,6 +563,7 @@ 43A536C011DBE3B9004A1712 /* Services */ = { isa = PBXGroup; children = ( + 7A6206911290046B00C638F3 /* Licorize */, 43A536C111DBE3B9004A1712 /* Delicious */, 43A536C411DBE3B9004A1712 /* Facebook */, 43A536DE11DBE3B9004A1712 /* Google Reader */, @@ -730,6 +734,15 @@ name = Localization; sourceTree = ""; }; + 7A6206911290046B00C638F3 /* Licorize */ = { + isa = PBXGroup; + children = ( + 7A6206921290046B00C638F3 /* SHKLicorize.h */, + 7A6206931290046B00C638F3 /* SHKLicorize.m */, + ); + path = Licorize; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -757,6 +770,7 @@ isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ShareKit" */; compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, @@ -865,6 +879,7 @@ 43C91DF511EBAE4800F31FAE /* SHKTumblr.m in Sources */, 43B934B511FE682600C9D3F3 /* SHKFBStreamDialog.m in Sources */, 432B147C11FF4B0700291B37 /* SHKPhotoAlbum.m in Sources */, + 7A6206941290046B00C638F3 /* SHKLicorize.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -896,7 +911,7 @@ INFOPLIST_FILE = "ShareKit-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 3.2; PRODUCT_NAME = ShareKit; - SDKROOT = iphoneos4.0; + SDKROOT = iphoneos4.1; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; From 18eb3244efd55ac2c9cdbeb0334b98e14b878d7e Mon Sep 17 00:00:00 2001 From: pippolino Date: Sun, 14 Nov 2010 14:16:30 +0100 Subject: [PATCH 43/50] Add Licorize Service configuration --- Classes/ShareKit/SHKConfig.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index c2aa3565..ce8165e2 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -85,7 +85,20 @@ // Append 'Shared With 'Signature to Email (and related forms) #define SHKSharedWithSignature 0 - +// Licorize - http://licorize.com +/* + The configuration is very similar as Twitter + + Callback URL (important to get right for OAuth users) + -- + 1. Open your application settings at http://developer.licorize.com/apps/ + 2. 'Application Type' should be set to BROWSER (not client) + 3. 'Callback URL' should match whatever you enter in SHKLicorizeCallbackUrl. The callback url doesn't have to be an actual existing url. The user will never get to it because ShareKit intercepts it before the user is redirected. It just needs to match. + */ +#define SHKLicorizeConsumerKey @"" +#define SHKLicorizeSecret @"" +#define SHKLicorizeCallbackUrl @"" // You need to set this if using OAuth, see note above (xAuth users can skip it) +#define SHKLicorizeUseXAuth 0 // To use xAuth, set to 1 /* UI Configuration : Basic From cc2a1e1af5b28c12724a3dd5e28dec5b27c49c3c Mon Sep 17 00:00:00 2001 From: Federico Soldani Date: Mon, 15 Nov 2010 10:47:42 +0100 Subject: [PATCH 44/50] Fix configuration instructions --- Classes/ShareKit/SHKConfig.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index ce8165e2..8c4fc2b2 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -87,11 +87,18 @@ // Licorize - http://licorize.com /* - The configuration is very similar as Twitter + Important Licorize settings to get right: + + Differences between OAuth and xAuth + -- + There are two types of authentication provided for Licorize clients, OAuth and xAuth, based on open standards. + OAuth is the default and will present a web page to log the user in. + xAuth is a simplified version of OAuth: xAuth presents a native entry form but you have to email the Licorize API team to enable xAuth for your app. + If your app has been approved for xAuth, set SHKLicorizeUseXAuth to 1. - Callback URL (important to get right for OAuth users) + Callback URL (it's important to get it right for OAuth users) -- - 1. Open your application settings at http://developer.licorize.com/apps/ + 1. Fill the form to get your application keys at http://licorize.com/api/ 2. 'Application Type' should be set to BROWSER (not client) 3. 'Callback URL' should match whatever you enter in SHKLicorizeCallbackUrl. The callback url doesn't have to be an actual existing url. The user will never get to it because ShareKit intercepts it before the user is redirected. It just needs to match. */ @@ -153,12 +160,12 @@ */ // A : show debug output -//#define SHKDebugShowLogs 1 -//#define SHKLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) +#define SHKDebugShowLogs 1 +#define SHKLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) // B : hide debug output -#define SHKDebugShowLogs 0 -#define SHKLog( s, ... ) +//#define SHKDebugShowLogs 0 +//#define SHKLog( s, ... ) From 3a7a558a26ea352f283981839e3fe56fbdbff85a Mon Sep 17 00:00:00 2001 From: Federico Soldani Date: Mon, 15 Nov 2010 10:48:39 +0100 Subject: [PATCH 45/50] Fix OAuth urls --- Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m index 63a7044e..95cee8bc 100644 --- a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m +++ b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m @@ -84,8 +84,8 @@ - (id)init { // You do not need to edit these, they are the same for everyone - self.requestURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/authorize"]; - self.authorizeURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/request_token"]; + self.requestURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/request_token"]; + self.authorizeURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/authorize"]; self.accessURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/access_token"]; self.signatureProvider = [[[OAHMAC_SHA1SignatureProvider alloc] init] autorelease]; From e0e2e9b345c8e70a135e34c156a9e61fa200ed57 Mon Sep 17 00:00:00 2001 From: pippolino Date: Mon, 15 Nov 2010 10:58:13 +0100 Subject: [PATCH 46/50] Indentetion --- Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m index 95cee8bc..5809559d 100644 --- a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m +++ b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m @@ -132,8 +132,6 @@ - (void)shareFormValidate:(SHKCustomFormController *)form { [form saveForm]; } - - #pragma mark - #pragma mark Implementation From d8976cd30752d474c0ec10479267da1989671c77 Mon Sep 17 00:00:00 2001 From: pippolino Date: Mon, 15 Nov 2010 10:58:59 +0100 Subject: [PATCH 47/50] Indentetion --- Classes/ShareKit/SHKConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 8c4fc2b2..25e961e6 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -95,7 +95,7 @@ OAuth is the default and will present a web page to log the user in. xAuth is a simplified version of OAuth: xAuth presents a native entry form but you have to email the Licorize API team to enable xAuth for your app. If your app has been approved for xAuth, set SHKLicorizeUseXAuth to 1. - + Callback URL (it's important to get it right for OAuth users) -- 1. Fill the form to get your application keys at http://licorize.com/api/ From a9663433ac9028a6177fb1a1def357dfad242a53 Mon Sep 17 00:00:00 2001 From: pippolino Date: Mon, 15 Nov 2010 11:02:09 +0100 Subject: [PATCH 48/50] Remove debug output --- Classes/ShareKit/SHKConfig.h | 8 ++++---- .../Sharers/Services/Licorize/SHKLicorize.m | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 25e961e6..49a91afe 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -160,12 +160,12 @@ */ // A : show debug output -#define SHKDebugShowLogs 1 -#define SHKLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) +//#define SHKDebugShowLogs 1 +//#define SHKLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] ) // B : hide debug output -//#define SHKDebugShowLogs 0 -//#define SHKLog( s, ... ) +#define SHKDebugShowLogs 0 +#define SHKLog( s, ... ) diff --git a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m index 5809559d..411e7c8d 100644 --- a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m +++ b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m @@ -42,11 +42,11 @@ + (BOOL)canShare { #pragma mark - #pragma mark Authorization -- (BOOL)isAuthorized { +- (BOOL)isAuthorized { return [self restoreAccessToken]; } -- (void)promptAuthorization { +- (void)promptAuthorization { if (xAuth) { [super authorizationFormShow]; // xAuth process } else { @@ -70,7 +70,7 @@ - (void)authorizationFormValidate:(SHKFormController *)form { #pragma mark Authentication - (id)init { - if (self = [super init]) { + if (self = [super init]) { // OAUTH self.consumerKey = SHKLicorizeConsumerKey; self.secretKey = SHKLicorizeSecret; @@ -89,11 +89,11 @@ - (id)init { self.accessURL = [NSURL URLWithString:@"http://api.licorize.com/oauth/access_token"]; self.signatureProvider = [[[OAHMAC_SHA1SignatureProvider alloc] init] autorelease]; - } + } return self; } -- (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest { +- (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest { if (xAuth) { NSDictionary *formValues = [pendingForm formValues]; @@ -111,7 +111,7 @@ - (void)tokenAccessModifyRequest:(OAMutableURLRequest *)oRequest { } // Validate the user input on the share form -- (void)shareFormValidate:(SHKCustomFormController *)form { +- (void)shareFormValidate:(SHKCustomFormController *)form { /* Services should subclass this if they need to validate any data before sending. @@ -136,7 +136,7 @@ - (void)shareFormValidate:(SHKCustomFormController *)form { #pragma mark Implementation // Send the share item to the server -- (BOOL)send { +- (BOOL)send { if (![self validateItem]) return NO; From b89d911ce9610bc1503b316697c4ccb3c7f79418 Mon Sep 17 00:00:00 2001 From: pippolino Date: Mon, 15 Nov 2010 17:32:39 +0100 Subject: [PATCH 49/50] Add multiple type strip --- .../Sharers/Services/Licorize/SHKLicorize.m | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m index 411e7c8d..af4c690d 100644 --- a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m +++ b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m @@ -7,6 +7,7 @@ #import "SHKLicorize.h" @interface SHKLicorize () +NSString * StringOrDefault(NSString * value, NSString * defaultValue); NSString * UrlOrBlank(NSURL * value); BOOL SendDidSuccess(NSData * data); @end @@ -164,7 +165,7 @@ - (void)remindMeLater { signatureProvider:nil]; [oRequest setHTTPMethod:@"POST"]; - + OARequestParameter *urlParam = [[OARequestParameter alloc] initWithName:@"url" value:UrlOrBlank(item.URL)]; OARequestParameter *titleParam = [[OARequestParameter alloc] initWithName:@"title" @@ -200,7 +201,7 @@ - (void)saveStrip { OARequestParameter *textParam = [[OARequestParameter alloc] initWithName:@"notes" value:SHKStringOrBlank(item.text)]; OARequestParameter *typeParam = [[OARequestParameter alloc] initWithName:@"type" - value:@"NOTE"]; + value:StringOrDefault([item customValueForKey:@"type"], @"NOTE")]; OARequestParameter *tagsParam = [[OARequestParameter alloc] initWithName:@"tags" value:SHKStringOrBlank(item.tags)]; @@ -262,20 +263,24 @@ - (void)sendTicket:(OAServiceTicket *)ticket didFailWithError:(NSError *)error { #pragma mark - #pragma mark Utilities +NSString * StringOrDefault(NSString * value, NSString * defaultValue) { + return value == nil ? defaultValue : value; +} + NSString * UrlOrBlank(NSURL * value) { return value == nil ? @"" : [value absoluteString]; } BOOL SendDidSuccess(NSData * data) { NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; - + NSScanner *scanner = [NSScanner scannerWithString:string]; - + NSString *success = @"true"; // skip until success message [scanner scanUpToString:@"\"ok\":" intoString:nil]; - + if ([scanner scanString:@"\"ok\":" intoString:nil]) { // get the message until the closing double quotes [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@","] intoString:&success]; @@ -286,7 +291,7 @@ BOOL SendDidSuccess(NSData * data) { } else { return NO; } - + } -@end +@end \ No newline at end of file From 1b6175489547d03e07c9b931e40e7fe2753c3ff1 Mon Sep 17 00:00:00 2001 From: pippolino Date: Thu, 18 Nov 2010 16:06:31 +0100 Subject: [PATCH 50/50] Change Text --- Classes/ShareKit/SHKConfig.h | 6 ------ Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Classes/ShareKit/SHKConfig.h b/Classes/ShareKit/SHKConfig.h index 49a91afe..c373684f 100644 --- a/Classes/ShareKit/SHKConfig.h +++ b/Classes/ShareKit/SHKConfig.h @@ -132,12 +132,6 @@ #define SHKModalPresentationStyle @"UIModalPresentationFormSheet" // See: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle #define SHKModalTransitionStyle @"UIModalTransitionStyleCoverVertical" // See: http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle -// ShareMenu Ordering -#define SHKShareMenuAlphabeticalOrder 1 // Setting this to 1 will show list in Alphabetical Order, setting to 0 will follow the order in SHKShares.plist - -// Append 'Shared With 'Signature to Email (and related forms) -#define SHKSharedWithSignature 0 - /* UI Configuration : Advanced ------ diff --git a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m index af4c690d..4f8b682d 100644 --- a/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m +++ b/Classes/ShareKit/Sharers/Services/Licorize/SHKLicorize.m @@ -59,7 +59,7 @@ - (void)promptAuthorization { #pragma mark xAuth + (NSString *)authorizationFormCaption { - return SHKLocalizedString(@"Create a free account at %@", @"Licorize.com"); + return SHKLocalizedString(@"For a free account sign up at %@", @"Licorize.com"); } - (void)authorizationFormValidate:(SHKFormController *)form {