├── .empty ├── .gitignore ├── LICENSE ├── README.md ├── lib ├── libcurl.a └── libssh2.a ├── objective-curl.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── objective-curl ├── .empty ├── en.lproj └── InfoPlist.strings ├── objective-curl-Info.plist ├── objective-curl-Prefix.pch ├── scripts ├── build-curl.sh ├── curl-7.30.0.patch └── curl-7.30.0.tar.gz └── src ├── CurlClient.h ├── CurlClientType.h ├── CurlConnectionDelegate.h ├── CurlFTP.h ├── CurlFTP.m ├── CurlFileTransfer.h ├── CurlFileTransfer.m ├── CurlObject.h ├── CurlObject.m ├── CurlOperation.h ├── CurlOperation.m ├── CurlRemoteFile.h ├── CurlRemoteFile.m ├── CurlRemoteFolder.h ├── CurlRemoteFolder.m ├── CurlRemoteObject.h ├── CurlRemoteObject.m ├── CurlS3.h ├── CurlS3.m ├── CurlS3DateUtil.h ├── CurlS3DateUtil.m ├── CurlS3ErrorCodes.h ├── CurlS3ErrorParser.h ├── CurlS3ErrorParser.m ├── CurlS3ListOperation.h ├── CurlS3ListOperation.m ├── CurlS3UploadOperation.h ├── CurlS3UploadOperation.m ├── CurlSCP.h ├── CurlSCP.m ├── CurlSFTP.h ├── CurlSFTP.m ├── CurlSSHUploadOperation.h ├── CurlSSHUploadOperation.m ├── CurlTransferStatus.h ├── CurlUpload.h ├── CurlUpload.m ├── CurlUploadDelegate.h ├── CurlUploadOperation.h ├── CurlUploadOperation.m ├── DDInvocationGrabber.h ├── DDInvocationGrabber.m ├── NSFileManager+MimeType.h ├── NSFileManager+MimeType.m ├── NSObject+DDExtensions.h ├── NSObject+DDExtensions.m ├── NSString+MD5.h ├── NSString+MD5.m ├── NSString+PathExtras.h ├── NSString+PathExtras.m ├── NSString+S3.h ├── NSString+S3.m ├── NSString+URLEncoding.h ├── NSString+URLEncoding.m ├── ftpparse.c ├── ftpparse.h ├── objective-curl.h └── patched-curl.h /.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrj/objective-curl/9d1c761aaf267aa3b3f4584e54726220f0de818e/.empty -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | objective-curl.xcodeproj/xcuserdata/ 3 | objective-curl.xcodeproj/project.xcworkspace/xcuserdata/ 4 | build/**/* 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | objective-curl is licensed under the MIT license. 2 | 3 | Copyright (c) 2009-2010, Nick Jensen, <[nickrjensen@gmail](mailto:nickrjensen@gmail.com)> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | 24 | [Curl](http://curl.haxx.se/) and [libcurl](http://curl.haxx.se/libcurl) are licensed under a MIT/X derivate license, see below. 25 | 26 | Copyright (c) 1996 - 2010, Daniel Stenberg, <[daniel@haxxe.se](mailto:daniel@haxxe.se)> 27 | 28 | All rights reserved. 29 | 30 | Permission to use, copy, modify, and distribute this software for any purpose 31 | with or without fee is hereby granted, provided that the above copyright 32 | notice and this permission notice appear in all copies. 33 | 34 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 35 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 36 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN 37 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 38 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 39 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 40 | OR OTHER DEALINGS IN THE SOFTWARE. 41 | 42 | Except as contained in this notice, the name of a copyright holder shall not 43 | be used in advertising or otherwise to promote the sale, use or other dealings 44 | in this Software without prior written authorization of the copyright holder. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The objective-curl framework provides an easy-to-use interface to [libcurl](http://curl.haxx.se/libcurl/c/) for Cocoa developers. Right now only uploading is supported and on the following protocols: FTP, SFTP, and Amazon S3 (HTTPS). There are a couple other frameworks out there that use libcurl for network operations but all subclass [NSURLHandle](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLHandle_Class/Reference/Reference.html), which has been deprecated since 10.4. This framework is designed to be used in more modern Cocoa applications and requires Mac OSX 10.5 or higher. 2 | 3 | All curl objects are subclasses of [NSObject](http://developer.apple.com/mac/library/documentation/cocoa/reference/Foundation/Classes/NSObject_Class/Reference/Reference.html). 4 | 5 | Threading is done with [NSOperation](http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/NSOperation_class/Reference/Reference.html) and [NSOperationQueue](http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/NSOperationQueue_class/Reference/Reference.html#//apple_ref/occ/cl/NSOperationQueue). (Added in OS X 10.5) 6 | 7 | The framework also utilizes common Cocoa delegate patterns. 8 | 9 | ## Simple Example 10 | 11 | CurlFTP *ftp = [[CurlFTP alloc] init]; 12 | 13 | // Also available are CurlSFTP, and CurlS3 classes which can be used in the same way. 14 | 15 | [ftp setVerbose:YES] 16 | [ftp setShowProgress:YES]; 17 | [ftp setAuthUsername:@"me"]; 18 | [ftp setAuthPassword:@"mypassword"]; 19 | 20 | // See the CurlDelegate protocol 21 | [ftp setDelegate:self]; 22 | 23 | // feel free to mix and match files and directories 24 | NSArray *filesToUpload = [[NSArray alloc] initWithObjects:@"/path/to/musicfile.mp3", 25 | @"/path/to/directory", 26 | @"/path/to/moviefile.avi", NULL]; 27 | // kick off the upload on a background thread 28 | [ftp uploadFilesAndDirectories:filesToUpload toHost:@"localhost" directory:@"~/tmp"]; 29 | 30 | ## OneWay 31 | 32 | The objective-curl framework is currently powering the [OneWay](http://goto11.net/oneway) application. 33 | 34 | ## License 35 | 36 | objective-curl is licensed under the MIT license. 37 | 38 | Copyright (c) 2009-2010, Nick Jensen, <[nickrjensen@gmail](mailto:nickrjensen@gmail.com)> 39 | 40 | Permission is hereby granted, free of charge, to any person obtaining a copy 41 | of this software and associated documentation files (the "Software"), to deal 42 | in the Software without restriction, including without limitation the rights 43 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 44 | copies of the Software, and to permit persons to whom the Software is 45 | furnished to do so, subject to the following conditions: 46 | 47 | The above copyright notice and this permission notice shall be included in 48 | all copies or substantial portions of the Software. 49 | 50 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 51 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 52 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 53 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 54 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 55 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 56 | THE SOFTWARE. 57 | 58 | 59 | [Curl](http://curl.haxx.se/) and [libcurl](http://curl.haxx.se/libcurl) are licensed under a MIT/X derivate license, see below. 60 | 61 | Copyright (c) 1996 - 2010, Daniel Stenberg, <[daniel@haxxe.se](mailto:daniel@haxxe.se)> 62 | 63 | All rights reserved. 64 | 65 | Permission to use, copy, modify, and distribute this software for any purpose 66 | with or without fee is hereby granted, provided that the above copyright 67 | notice and this permission notice appear in all copies. 68 | 69 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 70 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 71 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN 72 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 73 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 74 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 75 | OR OTHER DEALINGS IN THE SOFTWARE. 76 | 77 | Except as contained in this notice, the name of a copyright holder shall not 78 | be used in advertising or otherwise to promote the sale, use or other dealings 79 | in this Software without prior written authorization of the copyright holder. -------------------------------------------------------------------------------- /lib/libcurl.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrj/objective-curl/9d1c761aaf267aa3b3f4584e54726220f0de818e/lib/libcurl.a -------------------------------------------------------------------------------- /lib/libssh2.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrj/objective-curl/9d1c761aaf267aa3b3f4584e54726220f0de818e/lib/libssh2.a -------------------------------------------------------------------------------- /objective-curl.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0B4F461817698E44008BC7B3 /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B4F461717698E44008BC7B3 /* libssl.dylib */; }; 11 | 0B4F461D17698F1E008BC7B3 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B4F461B17698EBA008BC7B3 /* libz.dylib */; }; 12 | 0B5AE5F9176970D000B31A29 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B5AE5F8176970D000B31A29 /* Cocoa.framework */; }; 13 | 0B5AE603176970D000B31A29 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0B5AE601176970D000B31A29 /* InfoPlist.strings */; }; 14 | 0B5AE60E1769711100B31A29 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B5AE60D1769711100B31A29 /* Foundation.framework */; }; 15 | 0B5AE6491769719E00B31A29 /* CurlClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6101769719D00B31A29 /* CurlClient.h */; }; 16 | 0B5AE64A1769719E00B31A29 /* CurlClientType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6111769719D00B31A29 /* CurlClientType.h */; }; 17 | 0B5AE64B1769719E00B31A29 /* CurlConnectionDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6121769719D00B31A29 /* CurlConnectionDelegate.h */; }; 18 | 0B5AE64C1769719E00B31A29 /* CurlFileTransfer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6131769719D00B31A29 /* CurlFileTransfer.h */; }; 19 | 0B5AE64D1769719E00B31A29 /* CurlFileTransfer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6141769719D00B31A29 /* CurlFileTransfer.m */; }; 20 | 0B5AE64E1769719E00B31A29 /* CurlFTP.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6151769719D00B31A29 /* CurlFTP.h */; }; 21 | 0B5AE64F1769719E00B31A29 /* CurlFTP.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6161769719D00B31A29 /* CurlFTP.m */; }; 22 | 0B5AE6501769719E00B31A29 /* CurlObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6171769719E00B31A29 /* CurlObject.h */; }; 23 | 0B5AE6511769719E00B31A29 /* CurlObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6181769719E00B31A29 /* CurlObject.m */; }; 24 | 0B5AE6521769719E00B31A29 /* CurlOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6191769719E00B31A29 /* CurlOperation.h */; }; 25 | 0B5AE6531769719E00B31A29 /* CurlOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE61A1769719E00B31A29 /* CurlOperation.m */; }; 26 | 0B5AE6541769719E00B31A29 /* CurlRemoteFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE61B1769719E00B31A29 /* CurlRemoteFile.h */; }; 27 | 0B5AE6551769719E00B31A29 /* CurlRemoteFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE61C1769719E00B31A29 /* CurlRemoteFile.m */; }; 28 | 0B5AE6561769719E00B31A29 /* CurlRemoteFolder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE61D1769719E00B31A29 /* CurlRemoteFolder.h */; }; 29 | 0B5AE6571769719E00B31A29 /* CurlRemoteFolder.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE61E1769719E00B31A29 /* CurlRemoteFolder.m */; }; 30 | 0B5AE6581769719E00B31A29 /* CurlRemoteObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE61F1769719E00B31A29 /* CurlRemoteObject.h */; }; 31 | 0B5AE6591769719E00B31A29 /* CurlRemoteObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6201769719E00B31A29 /* CurlRemoteObject.m */; }; 32 | 0B5AE65A1769719E00B31A29 /* CurlS3.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6211769719E00B31A29 /* CurlS3.h */; }; 33 | 0B5AE65B1769719E00B31A29 /* CurlS3.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6221769719E00B31A29 /* CurlS3.m */; }; 34 | 0B5AE65C1769719E00B31A29 /* CurlS3DateUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6231769719E00B31A29 /* CurlS3DateUtil.h */; }; 35 | 0B5AE65D1769719E00B31A29 /* CurlS3DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6241769719E00B31A29 /* CurlS3DateUtil.m */; }; 36 | 0B5AE65E1769719E00B31A29 /* CurlS3ErrorCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6251769719E00B31A29 /* CurlS3ErrorCodes.h */; }; 37 | 0B5AE65F1769719E00B31A29 /* CurlS3ErrorParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6261769719E00B31A29 /* CurlS3ErrorParser.h */; }; 38 | 0B5AE6601769719E00B31A29 /* CurlS3ErrorParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6271769719E00B31A29 /* CurlS3ErrorParser.m */; }; 39 | 0B5AE6611769719E00B31A29 /* CurlS3ListOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6281769719E00B31A29 /* CurlS3ListOperation.h */; }; 40 | 0B5AE6621769719E00B31A29 /* CurlS3ListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6291769719E00B31A29 /* CurlS3ListOperation.m */; }; 41 | 0B5AE6631769719E00B31A29 /* CurlS3UploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE62A1769719E00B31A29 /* CurlS3UploadOperation.h */; }; 42 | 0B5AE6641769719E00B31A29 /* CurlS3UploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE62B1769719E00B31A29 /* CurlS3UploadOperation.m */; }; 43 | 0B5AE6651769719E00B31A29 /* CurlSCP.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE62C1769719E00B31A29 /* CurlSCP.h */; }; 44 | 0B5AE6661769719E00B31A29 /* CurlSCP.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE62D1769719E00B31A29 /* CurlSCP.m */; }; 45 | 0B5AE6671769719E00B31A29 /* CurlSFTP.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE62E1769719E00B31A29 /* CurlSFTP.h */; }; 46 | 0B5AE6681769719E00B31A29 /* CurlSFTP.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE62F1769719E00B31A29 /* CurlSFTP.m */; }; 47 | 0B5AE6691769719E00B31A29 /* CurlSSHUploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6301769719E00B31A29 /* CurlSSHUploadOperation.h */; }; 48 | 0B5AE66A1769719E00B31A29 /* CurlSSHUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6311769719E00B31A29 /* CurlSSHUploadOperation.m */; }; 49 | 0B5AE66B1769719E00B31A29 /* CurlTransferStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6321769719E00B31A29 /* CurlTransferStatus.h */; }; 50 | 0B5AE66C1769719E00B31A29 /* CurlUpload.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6331769719E00B31A29 /* CurlUpload.h */; }; 51 | 0B5AE66D1769719E00B31A29 /* CurlUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6341769719E00B31A29 /* CurlUpload.m */; }; 52 | 0B5AE66E1769719E00B31A29 /* CurlUploadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6351769719E00B31A29 /* CurlUploadDelegate.h */; }; 53 | 0B5AE66F1769719E00B31A29 /* CurlUploadOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6361769719E00B31A29 /* CurlUploadOperation.h */; }; 54 | 0B5AE6701769719E00B31A29 /* CurlUploadOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6371769719E00B31A29 /* CurlUploadOperation.m */; }; 55 | 0B5AE6711769719E00B31A29 /* DDInvocationGrabber.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6381769719E00B31A29 /* DDInvocationGrabber.h */; }; 56 | 0B5AE6721769719E00B31A29 /* DDInvocationGrabber.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6391769719E00B31A29 /* DDInvocationGrabber.m */; }; 57 | 0B5AE6731769719E00B31A29 /* ftpparse.c in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE63A1769719E00B31A29 /* ftpparse.c */; }; 58 | 0B5AE6741769719E00B31A29 /* ftpparse.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE63B1769719E00B31A29 /* ftpparse.h */; }; 59 | 0B5AE6751769719E00B31A29 /* NSFileManager+MimeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE63C1769719E00B31A29 /* NSFileManager+MimeType.h */; }; 60 | 0B5AE6761769719E00B31A29 /* NSFileManager+MimeType.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE63D1769719E00B31A29 /* NSFileManager+MimeType.m */; }; 61 | 0B5AE6771769719E00B31A29 /* NSObject+DDExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE63E1769719E00B31A29 /* NSObject+DDExtensions.h */; }; 62 | 0B5AE6781769719E00B31A29 /* NSObject+DDExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE63F1769719E00B31A29 /* NSObject+DDExtensions.m */; }; 63 | 0B5AE6791769719E00B31A29 /* NSString+MD5.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6401769719E00B31A29 /* NSString+MD5.h */; }; 64 | 0B5AE67A1769719E00B31A29 /* NSString+MD5.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6411769719E00B31A29 /* NSString+MD5.m */; }; 65 | 0B5AE67B1769719E00B31A29 /* NSString+PathExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6421769719E00B31A29 /* NSString+PathExtras.h */; }; 66 | 0B5AE67C1769719E00B31A29 /* NSString+PathExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6431769719E00B31A29 /* NSString+PathExtras.m */; }; 67 | 0B5AE67D1769719E00B31A29 /* NSString+S3.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6441769719E00B31A29 /* NSString+S3.h */; }; 68 | 0B5AE67E1769719E00B31A29 /* NSString+S3.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6451769719E00B31A29 /* NSString+S3.m */; }; 69 | 0B5AE67F1769719E00B31A29 /* NSString+URLEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6461769719E00B31A29 /* NSString+URLEncoding.h */; }; 70 | 0B5AE6801769719E00B31A29 /* NSString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5AE6471769719E00B31A29 /* NSString+URLEncoding.m */; }; 71 | 0B5AE6811769719E00B31A29 /* objective-curl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5AE6481769719E00B31A29 /* objective-curl.h */; }; 72 | 0B5AE685176971F100B31A29 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B5AE684176971F100B31A29 /* libcrypto.dylib */; }; 73 | 0BABBB1A176A39F20088A82D /* patched-curl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BABBB19176A39F20088A82D /* patched-curl.h */; }; 74 | 0BABBB1D176A3A5D0088A82D /* libcurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BABBB1B176A3A5D0088A82D /* libcurl.a */; }; 75 | 0BABBB1E176A3A5D0088A82D /* libssh2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BABBB1C176A3A5D0088A82D /* libssh2.a */; }; 76 | /* End PBXBuildFile section */ 77 | 78 | /* Begin PBXFileReference section */ 79 | 0B4F461717698E44008BC7B3 /* libssl.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.dylib; path = usr/lib/libssl.dylib; sourceTree = SDKROOT; }; 80 | 0B4F461B17698EBA008BC7B3 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 81 | 0B5AE5F5176970D000B31A29 /* objective-curl.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = "objective-curl.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | 0B5AE5F8176970D000B31A29 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 83 | 0B5AE600176970D000B31A29 /* objective-curl-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "objective-curl-Info.plist"; sourceTree = ""; }; 84 | 0B5AE602176970D000B31A29 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 85 | 0B5AE604176970D000B31A29 /* objective-curl-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "objective-curl-Prefix.pch"; sourceTree = ""; }; 86 | 0B5AE60D1769711100B31A29 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 87 | 0B5AE6101769719D00B31A29 /* CurlClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlClient.h; path = src/CurlClient.h; sourceTree = ""; }; 88 | 0B5AE6111769719D00B31A29 /* CurlClientType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlClientType.h; path = src/CurlClientType.h; sourceTree = ""; }; 89 | 0B5AE6121769719D00B31A29 /* CurlConnectionDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlConnectionDelegate.h; path = src/CurlConnectionDelegate.h; sourceTree = ""; }; 90 | 0B5AE6131769719D00B31A29 /* CurlFileTransfer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlFileTransfer.h; path = src/CurlFileTransfer.h; sourceTree = ""; }; 91 | 0B5AE6141769719D00B31A29 /* CurlFileTransfer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlFileTransfer.m; path = src/CurlFileTransfer.m; sourceTree = ""; }; 92 | 0B5AE6151769719D00B31A29 /* CurlFTP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlFTP.h; path = src/CurlFTP.h; sourceTree = ""; }; 93 | 0B5AE6161769719D00B31A29 /* CurlFTP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlFTP.m; path = src/CurlFTP.m; sourceTree = ""; }; 94 | 0B5AE6171769719E00B31A29 /* CurlObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlObject.h; path = src/CurlObject.h; sourceTree = ""; }; 95 | 0B5AE6181769719E00B31A29 /* CurlObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlObject.m; path = src/CurlObject.m; sourceTree = ""; }; 96 | 0B5AE6191769719E00B31A29 /* CurlOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlOperation.h; path = src/CurlOperation.h; sourceTree = ""; }; 97 | 0B5AE61A1769719E00B31A29 /* CurlOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlOperation.m; path = src/CurlOperation.m; sourceTree = ""; }; 98 | 0B5AE61B1769719E00B31A29 /* CurlRemoteFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlRemoteFile.h; path = src/CurlRemoteFile.h; sourceTree = ""; }; 99 | 0B5AE61C1769719E00B31A29 /* CurlRemoteFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlRemoteFile.m; path = src/CurlRemoteFile.m; sourceTree = ""; }; 100 | 0B5AE61D1769719E00B31A29 /* CurlRemoteFolder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlRemoteFolder.h; path = src/CurlRemoteFolder.h; sourceTree = ""; }; 101 | 0B5AE61E1769719E00B31A29 /* CurlRemoteFolder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlRemoteFolder.m; path = src/CurlRemoteFolder.m; sourceTree = ""; }; 102 | 0B5AE61F1769719E00B31A29 /* CurlRemoteObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlRemoteObject.h; path = src/CurlRemoteObject.h; sourceTree = ""; }; 103 | 0B5AE6201769719E00B31A29 /* CurlRemoteObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlRemoteObject.m; path = src/CurlRemoteObject.m; sourceTree = ""; }; 104 | 0B5AE6211769719E00B31A29 /* CurlS3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlS3.h; path = src/CurlS3.h; sourceTree = ""; }; 105 | 0B5AE6221769719E00B31A29 /* CurlS3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlS3.m; path = src/CurlS3.m; sourceTree = ""; }; 106 | 0B5AE6231769719E00B31A29 /* CurlS3DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlS3DateUtil.h; path = src/CurlS3DateUtil.h; sourceTree = ""; }; 107 | 0B5AE6241769719E00B31A29 /* CurlS3DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlS3DateUtil.m; path = src/CurlS3DateUtil.m; sourceTree = ""; }; 108 | 0B5AE6251769719E00B31A29 /* CurlS3ErrorCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlS3ErrorCodes.h; path = src/CurlS3ErrorCodes.h; sourceTree = ""; }; 109 | 0B5AE6261769719E00B31A29 /* CurlS3ErrorParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlS3ErrorParser.h; path = src/CurlS3ErrorParser.h; sourceTree = ""; }; 110 | 0B5AE6271769719E00B31A29 /* CurlS3ErrorParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlS3ErrorParser.m; path = src/CurlS3ErrorParser.m; sourceTree = ""; }; 111 | 0B5AE6281769719E00B31A29 /* CurlS3ListOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlS3ListOperation.h; path = src/CurlS3ListOperation.h; sourceTree = ""; }; 112 | 0B5AE6291769719E00B31A29 /* CurlS3ListOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlS3ListOperation.m; path = src/CurlS3ListOperation.m; sourceTree = ""; }; 113 | 0B5AE62A1769719E00B31A29 /* CurlS3UploadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlS3UploadOperation.h; path = src/CurlS3UploadOperation.h; sourceTree = ""; }; 114 | 0B5AE62B1769719E00B31A29 /* CurlS3UploadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlS3UploadOperation.m; path = src/CurlS3UploadOperation.m; sourceTree = ""; }; 115 | 0B5AE62C1769719E00B31A29 /* CurlSCP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlSCP.h; path = src/CurlSCP.h; sourceTree = ""; }; 116 | 0B5AE62D1769719E00B31A29 /* CurlSCP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlSCP.m; path = src/CurlSCP.m; sourceTree = ""; }; 117 | 0B5AE62E1769719E00B31A29 /* CurlSFTP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlSFTP.h; path = src/CurlSFTP.h; sourceTree = ""; }; 118 | 0B5AE62F1769719E00B31A29 /* CurlSFTP.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlSFTP.m; path = src/CurlSFTP.m; sourceTree = ""; }; 119 | 0B5AE6301769719E00B31A29 /* CurlSSHUploadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlSSHUploadOperation.h; path = src/CurlSSHUploadOperation.h; sourceTree = ""; }; 120 | 0B5AE6311769719E00B31A29 /* CurlSSHUploadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlSSHUploadOperation.m; path = src/CurlSSHUploadOperation.m; sourceTree = ""; }; 121 | 0B5AE6321769719E00B31A29 /* CurlTransferStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlTransferStatus.h; path = src/CurlTransferStatus.h; sourceTree = ""; }; 122 | 0B5AE6331769719E00B31A29 /* CurlUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlUpload.h; path = src/CurlUpload.h; sourceTree = ""; }; 123 | 0B5AE6341769719E00B31A29 /* CurlUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlUpload.m; path = src/CurlUpload.m; sourceTree = ""; }; 124 | 0B5AE6351769719E00B31A29 /* CurlUploadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlUploadDelegate.h; path = src/CurlUploadDelegate.h; sourceTree = ""; }; 125 | 0B5AE6361769719E00B31A29 /* CurlUploadOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CurlUploadOperation.h; path = src/CurlUploadOperation.h; sourceTree = ""; }; 126 | 0B5AE6371769719E00B31A29 /* CurlUploadOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CurlUploadOperation.m; path = src/CurlUploadOperation.m; sourceTree = ""; }; 127 | 0B5AE6381769719E00B31A29 /* DDInvocationGrabber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDInvocationGrabber.h; path = src/DDInvocationGrabber.h; sourceTree = ""; }; 128 | 0B5AE6391769719E00B31A29 /* DDInvocationGrabber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDInvocationGrabber.m; path = src/DDInvocationGrabber.m; sourceTree = ""; }; 129 | 0B5AE63A1769719E00B31A29 /* ftpparse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ftpparse.c; path = src/ftpparse.c; sourceTree = ""; }; 130 | 0B5AE63B1769719E00B31A29 /* ftpparse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ftpparse.h; path = src/ftpparse.h; sourceTree = ""; }; 131 | 0B5AE63C1769719E00B31A29 /* NSFileManager+MimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSFileManager+MimeType.h"; path = "src/NSFileManager+MimeType.h"; sourceTree = ""; }; 132 | 0B5AE63D1769719E00B31A29 /* NSFileManager+MimeType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSFileManager+MimeType.m"; path = "src/NSFileManager+MimeType.m"; sourceTree = ""; }; 133 | 0B5AE63E1769719E00B31A29 /* NSObject+DDExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSObject+DDExtensions.h"; path = "src/NSObject+DDExtensions.h"; sourceTree = ""; }; 134 | 0B5AE63F1769719E00B31A29 /* NSObject+DDExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSObject+DDExtensions.m"; path = "src/NSObject+DDExtensions.m"; sourceTree = ""; }; 135 | 0B5AE6401769719E00B31A29 /* NSString+MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+MD5.h"; path = "src/NSString+MD5.h"; sourceTree = ""; }; 136 | 0B5AE6411769719E00B31A29 /* NSString+MD5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+MD5.m"; path = "src/NSString+MD5.m"; sourceTree = ""; }; 137 | 0B5AE6421769719E00B31A29 /* NSString+PathExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+PathExtras.h"; path = "src/NSString+PathExtras.h"; sourceTree = ""; }; 138 | 0B5AE6431769719E00B31A29 /* NSString+PathExtras.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+PathExtras.m"; path = "src/NSString+PathExtras.m"; sourceTree = ""; }; 139 | 0B5AE6441769719E00B31A29 /* NSString+S3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+S3.h"; path = "src/NSString+S3.h"; sourceTree = ""; }; 140 | 0B5AE6451769719E00B31A29 /* NSString+S3.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+S3.m"; path = "src/NSString+S3.m"; sourceTree = ""; }; 141 | 0B5AE6461769719E00B31A29 /* NSString+URLEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+URLEncoding.h"; path = "src/NSString+URLEncoding.h"; sourceTree = ""; }; 142 | 0B5AE6471769719E00B31A29 /* NSString+URLEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+URLEncoding.m"; path = "src/NSString+URLEncoding.m"; sourceTree = ""; }; 143 | 0B5AE6481769719E00B31A29 /* objective-curl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "objective-curl.h"; path = "src/objective-curl.h"; sourceTree = ""; }; 144 | 0B5AE684176971F100B31A29 /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; }; 145 | 0BABBB19176A39F20088A82D /* patched-curl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "patched-curl.h"; path = "src/patched-curl.h"; sourceTree = ""; }; 146 | 0BABBB1B176A3A5D0088A82D /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcurl.a; path = lib/libcurl.a; sourceTree = ""; }; 147 | 0BABBB1C176A3A5D0088A82D /* libssh2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssh2.a; path = lib/libssh2.a; sourceTree = ""; }; 148 | /* End PBXFileReference section */ 149 | 150 | /* Begin PBXFrameworksBuildPhase section */ 151 | 0B5AE5F1176970D000B31A29 /* Frameworks */ = { 152 | isa = PBXFrameworksBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | 0B4F461D17698F1E008BC7B3 /* libz.dylib in Frameworks */, 156 | 0B4F461817698E44008BC7B3 /* libssl.dylib in Frameworks */, 157 | 0B5AE685176971F100B31A29 /* libcrypto.dylib in Frameworks */, 158 | 0B5AE60E1769711100B31A29 /* Foundation.framework in Frameworks */, 159 | 0B5AE5F9176970D000B31A29 /* Cocoa.framework in Frameworks */, 160 | 0BABBB1D176A3A5D0088A82D /* libcurl.a in Frameworks */, 161 | 0BABBB1E176A3A5D0088A82D /* libssh2.a in Frameworks */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | /* End PBXFrameworksBuildPhase section */ 166 | 167 | /* Begin PBXGroup section */ 168 | 0B5AE5EB176970D000B31A29 = { 169 | isa = PBXGroup; 170 | children = ( 171 | 0B5AE5FE176970D000B31A29 /* objective-curl */, 172 | 0B5AE5F7176970D000B31A29 /* Frameworks */, 173 | 0B5AE5F6176970D000B31A29 /* Products */, 174 | ); 175 | sourceTree = ""; 176 | }; 177 | 0B5AE5F6176970D000B31A29 /* Products */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | 0B5AE5F5176970D000B31A29 /* objective-curl.framework */, 181 | ); 182 | name = Products; 183 | sourceTree = ""; 184 | }; 185 | 0B5AE5F7176970D000B31A29 /* Frameworks */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | 0BABBB1B176A3A5D0088A82D /* libcurl.a */, 189 | 0BABBB1C176A3A5D0088A82D /* libssh2.a */, 190 | 0B4F461B17698EBA008BC7B3 /* libz.dylib */, 191 | 0B4F461717698E44008BC7B3 /* libssl.dylib */, 192 | 0B5AE684176971F100B31A29 /* libcrypto.dylib */, 193 | 0B5AE5F8176970D000B31A29 /* Cocoa.framework */, 194 | 0B5AE60D1769711100B31A29 /* Foundation.framework */, 195 | ); 196 | name = Frameworks; 197 | sourceTree = ""; 198 | }; 199 | 0B5AE5FE176970D000B31A29 /* objective-curl */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | 0B5AE60F1769712000B31A29 /* Source */, 203 | 0B5AE5FF176970D000B31A29 /* Supporting Files */, 204 | ); 205 | path = "objective-curl"; 206 | sourceTree = ""; 207 | }; 208 | 0B5AE5FF176970D000B31A29 /* Supporting Files */ = { 209 | isa = PBXGroup; 210 | children = ( 211 | 0B5AE600176970D000B31A29 /* objective-curl-Info.plist */, 212 | 0B5AE601176970D000B31A29 /* InfoPlist.strings */, 213 | 0B5AE604176970D000B31A29 /* objective-curl-Prefix.pch */, 214 | ); 215 | name = "Supporting Files"; 216 | sourceTree = ""; 217 | }; 218 | 0B5AE60F1769712000B31A29 /* Source */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | 0B5AE6101769719D00B31A29 /* CurlClient.h */, 222 | 0B5AE6111769719D00B31A29 /* CurlClientType.h */, 223 | 0B5AE6121769719D00B31A29 /* CurlConnectionDelegate.h */, 224 | 0B5AE6131769719D00B31A29 /* CurlFileTransfer.h */, 225 | 0B5AE6141769719D00B31A29 /* CurlFileTransfer.m */, 226 | 0B5AE6151769719D00B31A29 /* CurlFTP.h */, 227 | 0B5AE6161769719D00B31A29 /* CurlFTP.m */, 228 | 0B5AE6171769719E00B31A29 /* CurlObject.h */, 229 | 0B5AE6181769719E00B31A29 /* CurlObject.m */, 230 | 0B5AE6191769719E00B31A29 /* CurlOperation.h */, 231 | 0B5AE61A1769719E00B31A29 /* CurlOperation.m */, 232 | 0B5AE61B1769719E00B31A29 /* CurlRemoteFile.h */, 233 | 0B5AE61C1769719E00B31A29 /* CurlRemoteFile.m */, 234 | 0B5AE61D1769719E00B31A29 /* CurlRemoteFolder.h */, 235 | 0B5AE61E1769719E00B31A29 /* CurlRemoteFolder.m */, 236 | 0B5AE61F1769719E00B31A29 /* CurlRemoteObject.h */, 237 | 0B5AE6201769719E00B31A29 /* CurlRemoteObject.m */, 238 | 0B5AE6211769719E00B31A29 /* CurlS3.h */, 239 | 0B5AE6221769719E00B31A29 /* CurlS3.m */, 240 | 0B5AE6231769719E00B31A29 /* CurlS3DateUtil.h */, 241 | 0B5AE6241769719E00B31A29 /* CurlS3DateUtil.m */, 242 | 0B5AE6251769719E00B31A29 /* CurlS3ErrorCodes.h */, 243 | 0B5AE6261769719E00B31A29 /* CurlS3ErrorParser.h */, 244 | 0B5AE6271769719E00B31A29 /* CurlS3ErrorParser.m */, 245 | 0B5AE6281769719E00B31A29 /* CurlS3ListOperation.h */, 246 | 0B5AE6291769719E00B31A29 /* CurlS3ListOperation.m */, 247 | 0B5AE62A1769719E00B31A29 /* CurlS3UploadOperation.h */, 248 | 0B5AE62B1769719E00B31A29 /* CurlS3UploadOperation.m */, 249 | 0B5AE62C1769719E00B31A29 /* CurlSCP.h */, 250 | 0B5AE62D1769719E00B31A29 /* CurlSCP.m */, 251 | 0B5AE62E1769719E00B31A29 /* CurlSFTP.h */, 252 | 0B5AE62F1769719E00B31A29 /* CurlSFTP.m */, 253 | 0B5AE6301769719E00B31A29 /* CurlSSHUploadOperation.h */, 254 | 0B5AE6311769719E00B31A29 /* CurlSSHUploadOperation.m */, 255 | 0B5AE6321769719E00B31A29 /* CurlTransferStatus.h */, 256 | 0B5AE6331769719E00B31A29 /* CurlUpload.h */, 257 | 0B5AE6341769719E00B31A29 /* CurlUpload.m */, 258 | 0B5AE6351769719E00B31A29 /* CurlUploadDelegate.h */, 259 | 0B5AE6361769719E00B31A29 /* CurlUploadOperation.h */, 260 | 0B5AE6371769719E00B31A29 /* CurlUploadOperation.m */, 261 | 0B5AE6381769719E00B31A29 /* DDInvocationGrabber.h */, 262 | 0B5AE6391769719E00B31A29 /* DDInvocationGrabber.m */, 263 | 0B5AE63A1769719E00B31A29 /* ftpparse.c */, 264 | 0B5AE63B1769719E00B31A29 /* ftpparse.h */, 265 | 0B5AE63C1769719E00B31A29 /* NSFileManager+MimeType.h */, 266 | 0B5AE63D1769719E00B31A29 /* NSFileManager+MimeType.m */, 267 | 0B5AE63E1769719E00B31A29 /* NSObject+DDExtensions.h */, 268 | 0B5AE63F1769719E00B31A29 /* NSObject+DDExtensions.m */, 269 | 0B5AE6401769719E00B31A29 /* NSString+MD5.h */, 270 | 0B5AE6411769719E00B31A29 /* NSString+MD5.m */, 271 | 0B5AE6421769719E00B31A29 /* NSString+PathExtras.h */, 272 | 0B5AE6431769719E00B31A29 /* NSString+PathExtras.m */, 273 | 0B5AE6441769719E00B31A29 /* NSString+S3.h */, 274 | 0B5AE6451769719E00B31A29 /* NSString+S3.m */, 275 | 0B5AE6461769719E00B31A29 /* NSString+URLEncoding.h */, 276 | 0B5AE6471769719E00B31A29 /* NSString+URLEncoding.m */, 277 | 0B5AE6481769719E00B31A29 /* objective-curl.h */, 278 | 0BABBB19176A39F20088A82D /* patched-curl.h */, 279 | ); 280 | name = Source; 281 | sourceTree = ""; 282 | }; 283 | /* End PBXGroup section */ 284 | 285 | /* Begin PBXHeadersBuildPhase section */ 286 | 0B5AE5F2176970D000B31A29 /* Headers */ = { 287 | isa = PBXHeadersBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | 0B5AE6491769719E00B31A29 /* CurlClient.h in Headers */, 291 | 0B5AE64A1769719E00B31A29 /* CurlClientType.h in Headers */, 292 | 0B5AE64B1769719E00B31A29 /* CurlConnectionDelegate.h in Headers */, 293 | 0B5AE64C1769719E00B31A29 /* CurlFileTransfer.h in Headers */, 294 | 0B5AE64E1769719E00B31A29 /* CurlFTP.h in Headers */, 295 | 0B5AE6501769719E00B31A29 /* CurlObject.h in Headers */, 296 | 0B5AE6521769719E00B31A29 /* CurlOperation.h in Headers */, 297 | 0B5AE6541769719E00B31A29 /* CurlRemoteFile.h in Headers */, 298 | 0B5AE6561769719E00B31A29 /* CurlRemoteFolder.h in Headers */, 299 | 0B5AE6581769719E00B31A29 /* CurlRemoteObject.h in Headers */, 300 | 0B5AE65A1769719E00B31A29 /* CurlS3.h in Headers */, 301 | 0B5AE65C1769719E00B31A29 /* CurlS3DateUtil.h in Headers */, 302 | 0B5AE65E1769719E00B31A29 /* CurlS3ErrorCodes.h in Headers */, 303 | 0B5AE65F1769719E00B31A29 /* CurlS3ErrorParser.h in Headers */, 304 | 0B5AE6611769719E00B31A29 /* CurlS3ListOperation.h in Headers */, 305 | 0B5AE6631769719E00B31A29 /* CurlS3UploadOperation.h in Headers */, 306 | 0B5AE6651769719E00B31A29 /* CurlSCP.h in Headers */, 307 | 0B5AE6671769719E00B31A29 /* CurlSFTP.h in Headers */, 308 | 0B5AE6691769719E00B31A29 /* CurlSSHUploadOperation.h in Headers */, 309 | 0B5AE66B1769719E00B31A29 /* CurlTransferStatus.h in Headers */, 310 | 0B5AE66C1769719E00B31A29 /* CurlUpload.h in Headers */, 311 | 0B5AE66E1769719E00B31A29 /* CurlUploadDelegate.h in Headers */, 312 | 0B5AE66F1769719E00B31A29 /* CurlUploadOperation.h in Headers */, 313 | 0B5AE6711769719E00B31A29 /* DDInvocationGrabber.h in Headers */, 314 | 0B5AE6741769719E00B31A29 /* ftpparse.h in Headers */, 315 | 0B5AE6751769719E00B31A29 /* NSFileManager+MimeType.h in Headers */, 316 | 0B5AE6771769719E00B31A29 /* NSObject+DDExtensions.h in Headers */, 317 | 0B5AE6791769719E00B31A29 /* NSString+MD5.h in Headers */, 318 | 0B5AE67B1769719E00B31A29 /* NSString+PathExtras.h in Headers */, 319 | 0B5AE67D1769719E00B31A29 /* NSString+S3.h in Headers */, 320 | 0B5AE67F1769719E00B31A29 /* NSString+URLEncoding.h in Headers */, 321 | 0B5AE6811769719E00B31A29 /* objective-curl.h in Headers */, 322 | 0BABBB1A176A39F20088A82D /* patched-curl.h in Headers */, 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | /* End PBXHeadersBuildPhase section */ 327 | 328 | /* Begin PBXNativeTarget section */ 329 | 0B5AE5F4176970D000B31A29 /* objective-curl */ = { 330 | isa = PBXNativeTarget; 331 | buildConfigurationList = 0B5AE60A176970D000B31A29 /* Build configuration list for PBXNativeTarget "objective-curl" */; 332 | buildPhases = ( 333 | 0B5AE5F0176970D000B31A29 /* Sources */, 334 | 0B5AE5F1176970D000B31A29 /* Frameworks */, 335 | 0B5AE5F2176970D000B31A29 /* Headers */, 336 | 0B5AE5F3176970D000B31A29 /* Resources */, 337 | ); 338 | buildRules = ( 339 | ); 340 | dependencies = ( 341 | ); 342 | name = "objective-curl"; 343 | productName = "objective-curl"; 344 | productReference = 0B5AE5F5176970D000B31A29 /* objective-curl.framework */; 345 | productType = "com.apple.product-type.framework"; 346 | }; 347 | /* End PBXNativeTarget section */ 348 | 349 | /* Begin PBXProject section */ 350 | 0B5AE5EC176970D000B31A29 /* Project object */ = { 351 | isa = PBXProject; 352 | attributes = { 353 | LastUpgradeCheck = 0460; 354 | ORGANIZATIONNAME = nrj; 355 | }; 356 | buildConfigurationList = 0B5AE5EF176970D000B31A29 /* Build configuration list for PBXProject "objective-curl" */; 357 | compatibilityVersion = "Xcode 3.2"; 358 | developmentRegion = English; 359 | hasScannedForEncodings = 0; 360 | knownRegions = ( 361 | en, 362 | ); 363 | mainGroup = 0B5AE5EB176970D000B31A29; 364 | productRefGroup = 0B5AE5F6176970D000B31A29 /* Products */; 365 | projectDirPath = ""; 366 | projectRoot = ""; 367 | targets = ( 368 | 0B5AE5F4176970D000B31A29 /* objective-curl */, 369 | ); 370 | }; 371 | /* End PBXProject section */ 372 | 373 | /* Begin PBXResourcesBuildPhase section */ 374 | 0B5AE5F3176970D000B31A29 /* Resources */ = { 375 | isa = PBXResourcesBuildPhase; 376 | buildActionMask = 2147483647; 377 | files = ( 378 | 0B5AE603176970D000B31A29 /* InfoPlist.strings in Resources */, 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | /* End PBXResourcesBuildPhase section */ 383 | 384 | /* Begin PBXSourcesBuildPhase section */ 385 | 0B5AE5F0176970D000B31A29 /* Sources */ = { 386 | isa = PBXSourcesBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | 0B5AE64D1769719E00B31A29 /* CurlFileTransfer.m in Sources */, 390 | 0B5AE64F1769719E00B31A29 /* CurlFTP.m in Sources */, 391 | 0B5AE6511769719E00B31A29 /* CurlObject.m in Sources */, 392 | 0B5AE6531769719E00B31A29 /* CurlOperation.m in Sources */, 393 | 0B5AE6551769719E00B31A29 /* CurlRemoteFile.m in Sources */, 394 | 0B5AE6571769719E00B31A29 /* CurlRemoteFolder.m in Sources */, 395 | 0B5AE6591769719E00B31A29 /* CurlRemoteObject.m in Sources */, 396 | 0B5AE65B1769719E00B31A29 /* CurlS3.m in Sources */, 397 | 0B5AE65D1769719E00B31A29 /* CurlS3DateUtil.m in Sources */, 398 | 0B5AE6601769719E00B31A29 /* CurlS3ErrorParser.m in Sources */, 399 | 0B5AE6621769719E00B31A29 /* CurlS3ListOperation.m in Sources */, 400 | 0B5AE6641769719E00B31A29 /* CurlS3UploadOperation.m in Sources */, 401 | 0B5AE6661769719E00B31A29 /* CurlSCP.m in Sources */, 402 | 0B5AE6681769719E00B31A29 /* CurlSFTP.m in Sources */, 403 | 0B5AE66A1769719E00B31A29 /* CurlSSHUploadOperation.m in Sources */, 404 | 0B5AE66D1769719E00B31A29 /* CurlUpload.m in Sources */, 405 | 0B5AE6701769719E00B31A29 /* CurlUploadOperation.m in Sources */, 406 | 0B5AE6721769719E00B31A29 /* DDInvocationGrabber.m in Sources */, 407 | 0B5AE6731769719E00B31A29 /* ftpparse.c in Sources */, 408 | 0B5AE6761769719E00B31A29 /* NSFileManager+MimeType.m in Sources */, 409 | 0B5AE6781769719E00B31A29 /* NSObject+DDExtensions.m in Sources */, 410 | 0B5AE67A1769719E00B31A29 /* NSString+MD5.m in Sources */, 411 | 0B5AE67C1769719E00B31A29 /* NSString+PathExtras.m in Sources */, 412 | 0B5AE67E1769719E00B31A29 /* NSString+S3.m in Sources */, 413 | 0B5AE6801769719E00B31A29 /* NSString+URLEncoding.m in Sources */, 414 | ); 415 | runOnlyForDeploymentPostprocessing = 0; 416 | }; 417 | /* End PBXSourcesBuildPhase section */ 418 | 419 | /* Begin PBXVariantGroup section */ 420 | 0B5AE601176970D000B31A29 /* InfoPlist.strings */ = { 421 | isa = PBXVariantGroup; 422 | children = ( 423 | 0B5AE602176970D000B31A29 /* en */, 424 | ); 425 | name = InfoPlist.strings; 426 | sourceTree = ""; 427 | }; 428 | /* End PBXVariantGroup section */ 429 | 430 | /* Begin XCBuildConfiguration section */ 431 | 0B5AE608176970D000B31A29 /* Debug */ = { 432 | isa = XCBuildConfiguration; 433 | buildSettings = { 434 | ALWAYS_SEARCH_USER_PATHS = NO; 435 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 436 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 437 | CLANG_CXX_LIBRARY = "libc++"; 438 | CLANG_WARN_CONSTANT_CONVERSION = YES; 439 | CLANG_WARN_EMPTY_BODY = YES; 440 | CLANG_WARN_ENUM_CONVERSION = YES; 441 | CLANG_WARN_INT_CONVERSION = YES; 442 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 443 | COPY_PHASE_STRIP = NO; 444 | GCC_C_LANGUAGE_STANDARD = gnu99; 445 | GCC_DYNAMIC_NO_PIC = NO; 446 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 447 | GCC_OPTIMIZATION_LEVEL = 0; 448 | GCC_PREPROCESSOR_DEFINITIONS = ( 449 | "DEBUG=1", 450 | "$(inherited)", 451 | ); 452 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 453 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 454 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 455 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 456 | GCC_WARN_UNUSED_VARIABLE = YES; 457 | MACOSX_DEPLOYMENT_TARGET = 10.8; 458 | ONLY_ACTIVE_ARCH = YES; 459 | SDKROOT = macosx; 460 | }; 461 | name = Debug; 462 | }; 463 | 0B5AE609176970D000B31A29 /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | ALWAYS_SEARCH_USER_PATHS = NO; 467 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 468 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 469 | CLANG_CXX_LIBRARY = "libc++"; 470 | CLANG_WARN_CONSTANT_CONVERSION = YES; 471 | CLANG_WARN_EMPTY_BODY = YES; 472 | CLANG_WARN_ENUM_CONVERSION = YES; 473 | CLANG_WARN_INT_CONVERSION = YES; 474 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 475 | COPY_PHASE_STRIP = YES; 476 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 477 | GCC_C_LANGUAGE_STANDARD = gnu99; 478 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 479 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 480 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 481 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 482 | GCC_WARN_UNUSED_VARIABLE = YES; 483 | MACOSX_DEPLOYMENT_TARGET = 10.8; 484 | SDKROOT = macosx; 485 | }; 486 | name = Release; 487 | }; 488 | 0B5AE60B176970D000B31A29 /* Debug */ = { 489 | isa = XCBuildConfiguration; 490 | buildSettings = { 491 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 492 | COMBINE_HIDPI_IMAGES = YES; 493 | DYLIB_COMPATIBILITY_VERSION = 1; 494 | DYLIB_CURRENT_VERSION = 1; 495 | FRAMEWORK_VERSION = A; 496 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 497 | GCC_PREFIX_HEADER = "objective-curl/objective-curl-Prefix.pch"; 498 | INFOPLIST_FILE = "objective-curl/objective-curl-Info.plist"; 499 | LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/lib\""; 500 | MACOSX_DEPLOYMENT_TARGET = 10.7; 501 | PRODUCT_NAME = "$(TARGET_NAME)"; 502 | WRAPPER_EXTENSION = framework; 503 | }; 504 | name = Debug; 505 | }; 506 | 0B5AE60C176970D000B31A29 /* Release */ = { 507 | isa = XCBuildConfiguration; 508 | buildSettings = { 509 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 510 | COMBINE_HIDPI_IMAGES = YES; 511 | DYLIB_COMPATIBILITY_VERSION = 1; 512 | DYLIB_CURRENT_VERSION = 1; 513 | FRAMEWORK_VERSION = A; 514 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 515 | GCC_PREFIX_HEADER = "objective-curl/objective-curl-Prefix.pch"; 516 | INFOPLIST_FILE = "objective-curl/objective-curl-Info.plist"; 517 | LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/lib\""; 518 | MACOSX_DEPLOYMENT_TARGET = 10.7; 519 | PRODUCT_NAME = "$(TARGET_NAME)"; 520 | WRAPPER_EXTENSION = framework; 521 | }; 522 | name = Release; 523 | }; 524 | /* End XCBuildConfiguration section */ 525 | 526 | /* Begin XCConfigurationList section */ 527 | 0B5AE5EF176970D000B31A29 /* Build configuration list for PBXProject "objective-curl" */ = { 528 | isa = XCConfigurationList; 529 | buildConfigurations = ( 530 | 0B5AE608176970D000B31A29 /* Debug */, 531 | 0B5AE609176970D000B31A29 /* Release */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | 0B5AE60A176970D000B31A29 /* Build configuration list for PBXNativeTarget "objective-curl" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | 0B5AE60B176970D000B31A29 /* Debug */, 540 | 0B5AE60C176970D000B31A29 /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | /* End XCConfigurationList section */ 546 | }; 547 | rootObject = 0B5AE5EC176970D000B31A29 /* Project object */; 548 | } 549 | -------------------------------------------------------------------------------- /objective-curl.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /objective-curl/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrj/objective-curl/9d1c761aaf267aa3b3f4584e54726220f0de818e/objective-curl/.empty -------------------------------------------------------------------------------- /objective-curl/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /objective-curl/objective-curl-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.whynotnick.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 2 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 0.0.1 25 | NSHumanReadableCopyright 26 | Copyright © 2013 nrj. All rights reserved. 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /objective-curl/objective-curl-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'objective-curl' target in the 'objective-curl' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /objective-curl/scripts/build-curl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | OSX_SDK_PATH="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk" 4 | export CFLAGS="-O -g -isysroot $OSX_SDK_PATH -mmacosx-version-min=10.7 -arch x86_64" 5 | 6 | CURL_BUILD="curl-7.30.0" 7 | 8 | if [ -d $CURL_BUILD ]; then 9 | rm -rf $CURL_BUILD 10 | fi 11 | 12 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 13 | 14 | PROJECT_LIBS="$SCRIPT_DIR/../lib" 15 | PROJECT_INCLUDE="$SCRIPT_DIR/../include" 16 | 17 | export CPPFLAGS="-I$PROJECT_INCLUDE" 18 | export LDFLAGS="-L$PROJECT_LIBS" 19 | export LIBS="-lssh2 -lssl -lz" 20 | 21 | # Extract libcurl source 22 | tar xzvf $CURL_BUILD.tar.gz 23 | cp $CURL_BUILD.patch $CURL_BUILD 24 | 25 | # Change to the source dir 26 | cd $CURL_BUILD 27 | 28 | # Apply our patch 29 | patch -p1 -i $CURL_BUILD.patch 30 | 31 | # Build libcurl 32 | ./configure --enable-static \ 33 | --disable-shared \ 34 | --disable-ldap \ 35 | --with-libssh2 36 | make 37 | 38 | # Copy the static lib into the project 39 | CURL_STATIC_LIB_PATH="lib/.libs/libcurl.a" 40 | echo "Copying $CURL_STATIC_LIB_PATH => $PROJECT_LIBS" 41 | cp $CURL_STATIC_LIB_PATH $PROJECT_LIBS 42 | 43 | # Cleanup 44 | cd .. 45 | echo "Removing directory $CURL_BUILD" 46 | # rm -rf $CURL_BUILD -------------------------------------------------------------------------------- /objective-curl/scripts/curl-7.30.0.patch: -------------------------------------------------------------------------------- 1 | diff -rupN curl-7.30.0/include/curl/curl.h curl-7.30.0-patched/include/curl/curl.h 2 | --- curl-7.30.0/include/curl/curl.h 2013-04-11 14:46:54.000000000 -0400 3 | +++ curl-7.30.0-patched/include/curl/curl.h 2013-06-12 14:52:39.000000000 -0400 4 | @@ -157,6 +157,7 @@ struct curl_httppost { 5 | }; 6 | 7 | typedef int (*curl_progress_callback)(void *clientp, 8 | + int connected, 9 | double dltotal, 10 | double dlnow, 11 | double ultotal, 12 | diff -rupN curl-7.30.0/lib/progress.c curl-7.30.0-patched/lib/progress.c 13 | --- curl-7.30.0/lib/progress.c 2013-01-16 17:05:56.000000000 -0500 14 | +++ curl-7.30.0-patched/lib/progress.c 2013-06-12 14:54:10.000000000 -0400 15 | @@ -364,6 +364,7 @@ int Curl_pgrsUpdate(struct connectdata * 16 | /* There's a callback set, so we call that instead of writing 17 | anything ourselves. This really is the way to go. */ 18 | result= data->set.fprogress(data->set.progress_client, 19 | + data->progress.flags ? 1 : 0, 20 | (double)data->progress.size_dl, 21 | (double)data->progress.downloaded, 22 | (double)data->progress.size_ul, 23 | -------------------------------------------------------------------------------- /objective-curl/scripts/curl-7.30.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrj/objective-curl/9d1c761aaf267aa3b3f4584e54726220f0de818e/objective-curl/scripts/curl-7.30.0.tar.gz -------------------------------------------------------------------------------- /objective-curl/src/CurlClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlClient.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | 9 | @class CurlUpload; 10 | 11 | @protocol CurlClient 12 | 13 | - (SecProtocolType)protocol; 14 | 15 | - (int)clientType; 16 | 17 | - (id)delegate; 18 | - (void)setDelegate:(id)delegate; 19 | 20 | - (void)setVerbose:(BOOL)verbose; 21 | - (BOOL)verbose; 22 | 23 | - (void)setShowProgress:(BOOL)showProgress; 24 | - (BOOL)showProgress; 25 | 26 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username; 27 | 28 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password; 29 | 30 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password directory:(NSString *)directory; 31 | 32 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password directory:(NSString *)directory port:(int)port; 33 | 34 | - (void)upload:(CurlUpload *)record; 35 | 36 | - (CURL *)newHandle; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /objective-curl/src/CurlClientType.h: -------------------------------------------------------------------------------- 1 | /* 2 | * CurlClientType.h 3 | * objective-curl 4 | * 5 | * Copyright 2010 Nick Jensen 6 | * 7 | */ 8 | 9 | 10 | typedef enum { 11 | CURL_CLIENT_SFTP, 12 | CURL_CLIENT_FTP, 13 | CURL_CLIENT_S3 14 | } CurlClientType; -------------------------------------------------------------------------------- /objective-curl/src/CurlConnectionDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlConnectionDelegate.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | 9 | @class CurlRemoteObject; 10 | 11 | 12 | @protocol CurlConnectionDelegate 13 | 14 | /* 15 | * Called when curl starts the connection process. 16 | */ 17 | - (void)curlIsConnecting:(CurlRemoteObject *)record; 18 | 19 | 20 | /* 21 | * Called when curl successfully connects. 22 | */ 23 | - (void)curlDidConnect:(CurlRemoteObject *)record; 24 | 25 | 26 | @end -------------------------------------------------------------------------------- /objective-curl/src/CurlFTP.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlFTP.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlObject.h" 10 | #import "CurlClient.h" 11 | 12 | 13 | @class CurlUpload, CurlRemoteFolder; 14 | 15 | 16 | @interface CurlFTP : CurlObject 17 | { 18 | NSMutableDictionary *directoryListCache; 19 | } 20 | 21 | - (NSString *)protocolPrefix; 22 | - (int)defaultPort; 23 | 24 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username; 25 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password; 26 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password directory:(NSString *)directory; 27 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password directory:(NSString *)directory port:(int)port; 28 | - (void)upload:(CurlUpload *)record; 29 | 30 | static size_t handleDirectoryList(void *ptr, size_t size, size_t nmemb, NSMutableArray *list); 31 | 32 | - (CurlRemoteFolder *)listRemoteDirectory:(NSString *)directory onHost:(NSString *)host; 33 | - (CurlRemoteFolder *)listRemoteDirectory:(NSString *)directory onHost:(NSString *)host forceReload:(BOOL)reload; 34 | - (CurlRemoteFolder *)listRemoteDirectory:(NSString *)directory onHost:(NSString *)host forceReload:(BOOL)reload port:(int)port; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /objective-curl/src/CurlFTP.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlFTP.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlFTP.h" 9 | #import "CurlClientType.h" 10 | #import "CurlUploadOperation.h" 11 | #import "CurlUpload.h" 12 | #import "NSString+PathExtras.h" 13 | 14 | 15 | @implementation CurlFTP 16 | 17 | 18 | /* 19 | * Initialize a directory list cache and other property defaults; 20 | */ 21 | - (id)init 22 | { 23 | if (self = [super init]) 24 | { 25 | [self setProtocol:kSecProtocolTypeFTP]; 26 | 27 | directoryListCache = [[NSMutableDictionary alloc] init]; 28 | } 29 | 30 | return self; 31 | } 32 | 33 | 34 | /* 35 | * Cleanup. 36 | */ 37 | - (void)dealloc 38 | { 39 | [directoryListCache release]; 40 | 41 | [super dealloc]; 42 | } 43 | 44 | 45 | - (NSString *)protocolPrefix 46 | { 47 | return @"ftp"; 48 | } 49 | 50 | 51 | - (int)defaultPort 52 | { 53 | return 21; 54 | } 55 | 56 | 57 | - (int)clientType 58 | { 59 | return CURL_CLIENT_FTP; 60 | } 61 | 62 | 63 | 64 | /* 65 | * Recursively upload a list of files and directories using the specified host and the users home directory. 66 | */ 67 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username 68 | { 69 | return [self uploadFilesAndDirectories:filesAndDirectories 70 | toHost:hostname 71 | username:username 72 | password:@"" 73 | directory:@"" 74 | port:[self defaultPort]]; 75 | } 76 | 77 | 78 | /* 79 | * Recursively upload a list of files and directories using the specified host and directory. 80 | */ 81 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password 82 | { 83 | return [self uploadFilesAndDirectories:filesAndDirectories 84 | toHost:hostname 85 | username:username 86 | password:password 87 | directory:@"" 88 | port:[self defaultPort]]; 89 | } 90 | 91 | 92 | /* 93 | * Recursively upload a list of files and directories using the specified host, directory and port number. The associated Upload object 94 | * is returned, however not retained. 95 | */ 96 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password directory:(NSString *)directory 97 | { 98 | return [self uploadFilesAndDirectories:filesAndDirectories 99 | toHost:hostname 100 | username:username 101 | password:password 102 | directory:directory 103 | port:[self defaultPort]]; 104 | } 105 | 106 | - (CurlUpload *)uploadFilesAndDirectories:(NSArray *)filesAndDirectories toHost:(NSString *)hostname username:(NSString *)username password:(NSString *)password directory:(NSString *)directory port:(int)port 107 | { 108 | CurlUpload *upload = [[[CurlUpload alloc] init] autorelease]; 109 | 110 | [upload setProtocol:[self protocol]]; 111 | [upload setProtocolPrefix:[self protocolPrefix]]; 112 | [upload setClientType:[self clientType]]; 113 | [upload setLocalFiles:filesAndDirectories]; 114 | [upload setHostname:hostname]; 115 | [upload setUsername:username]; 116 | [upload setPassword:password]; 117 | [upload setPath:[directory stringByRemovingTildePrefix]]; 118 | [upload setPort:port]; 119 | 120 | [self upload:upload]; 121 | 122 | return upload; 123 | } 124 | 125 | - (void)upload:(CurlUpload *)record 126 | { 127 | CurlUploadOperation *op = [[CurlUploadOperation alloc] initWithHandle:[self newHandle] delegate:delegate]; 128 | 129 | [record setProgress:0]; 130 | [record setStatus:CURL_TRANSFER_STATUS_QUEUED]; 131 | [record setConnected:NO]; 132 | [record setCancelled:NO]; 133 | 134 | [op setUpload:record]; 135 | [operationQueue addOperation:op]; 136 | [op release]; 137 | } 138 | 139 | 140 | /* 141 | * Returns an array of files that exist in a remote directory. Will use items in the directoryListCache if they exist. Uses 142 | * the default FTP port. 143 | */ 144 | - (CurlRemoteFolder *)listRemoteDirectory:(NSString *)directory onHost:(NSString *)host 145 | { 146 | return [self listRemoteDirectory:directory 147 | onHost:host 148 | forceReload:NO 149 | port:[self defaultPort]]; 150 | } 151 | 152 | 153 | /* 154 | * Returns an array of files that exist in a remote directory. The forceReload flag will bypass using the directoryListCache and 155 | * always return a fresh listing from the specified server. Uses the default FTP port. 156 | */ 157 | - (CurlRemoteFolder *)listRemoteDirectory:(NSString *)directory onHost:(NSString *)host forceReload:(BOOL)reload 158 | { 159 | return [self listRemoteDirectory:directory 160 | onHost:host 161 | forceReload:reload 162 | port:[self defaultPort]]; 163 | } 164 | 165 | 166 | /* 167 | * Returns an array of files that exist in a remote directory. The forceReload flag will bypass using the directoryListCache and 168 | * always return a fresh listing from the specified server and port number. 169 | */ 170 | - (CurlRemoteFolder *)listRemoteDirectory:(NSString *)directory onHost:(NSString *)host forceReload:(BOOL)reload port:(int)port 171 | { 172 | // RemoteFolder *folder = [[[RemoteFolder alloc] init] autorelease]; 173 | // 174 | // [folder setProtocol:[self protocolType]]; 175 | // [folder setHostname:host]; 176 | // [folder setPort:port]; 177 | // [folder setPath:[directory pathForFTP]]; 178 | // [folder setForceReload:reload]; 179 | // 180 | // 181 | // ListOperation *op = [[ListOperation alloc] initWithClient:self transfer:folder]; 182 | // 183 | // [op setFolder:folder]; 184 | // 185 | // [operationQueue addOperation:op]; 186 | // 187 | // return folder; 188 | return nil; 189 | } 190 | 191 | 192 | @end 193 | -------------------------------------------------------------------------------- /objective-curl/src/CurlFileTransfer.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlFileTransfer.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | #import 12 | 13 | @interface CurlFileTransfer : NSObject 14 | { 15 | NSString *localPath; 16 | NSString *remotePath; 17 | 18 | struct curl_slist *headers; 19 | struct curl_slist *postQuote; 20 | 21 | BOOL isEmptyDirectory; 22 | BOOL fileNotFound; 23 | 24 | int percentComplete; 25 | double totalBytes; 26 | double totalBytesUploaded; 27 | } 28 | 29 | 30 | @property(readwrite, copy) NSString *localPath; 31 | 32 | @property(readwrite, copy) NSString *remotePath; 33 | 34 | @property(readwrite, assign) BOOL isEmptyDirectory; 35 | 36 | @property(readwrite, assign) BOOL fileNotFound; 37 | 38 | @property(readwrite, assign) int percentComplete; 39 | 40 | @property(readwrite, assign) double totalBytes; 41 | 42 | @property(readwrite, assign) double totalBytesUploaded; 43 | 44 | 45 | - (id)initWithLocalPath:(NSString *)aLocalPath remotePath:(NSString *)aRemotePath; 46 | 47 | - (struct curl_slist *)headers; 48 | 49 | - (void)appendHeader:(const char *)header; 50 | 51 | - (void)cleanupHeaders; 52 | 53 | - (struct curl_slist *)postQuote; 54 | 55 | - (void)appendPostQuote:(const char *)quote; 56 | 57 | - (void)cleanupPostQuotes; 58 | 59 | - (FILE *)getHandle; 60 | 61 | - (int)getInfo:(struct stat *)info; 62 | 63 | - (NSString *)getEmptyFilePath; 64 | 65 | + (NSString *)emptyFilename; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /objective-curl/src/CurlFileTransfer.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlFileTransfer.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlFileTransfer.h" 9 | 10 | 11 | @implementation CurlFileTransfer 12 | 13 | 14 | @synthesize localPath; 15 | 16 | @synthesize remotePath; 17 | 18 | @synthesize isEmptyDirectory; 19 | 20 | @synthesize percentComplete; 21 | 22 | @synthesize totalBytes; 23 | 24 | @synthesize totalBytesUploaded; 25 | 26 | @synthesize fileNotFound; 27 | 28 | 29 | - (id)initWithLocalPath:(NSString *)aLocalPath remotePath:(NSString *)aRemotePath 30 | { 31 | if (self = [super init]) 32 | { 33 | [self setLocalPath:aLocalPath]; 34 | [self setRemotePath:aRemotePath]; 35 | 36 | headers = NULL; 37 | postQuote = NULL; 38 | 39 | percentComplete = 0; 40 | totalBytes = 0; 41 | totalBytesUploaded = 0; 42 | } 43 | 44 | return self; 45 | } 46 | 47 | 48 | - (void)dealloc 49 | { 50 | [localPath release]; localPath = nil; 51 | [remotePath release]; remotePath = nil; 52 | if (headers) { 53 | curl_slist_free_all(headers); headers = nil; 54 | } 55 | if (postQuote) { 56 | curl_slist_free_all(postQuote); postQuote = nil; 57 | } 58 | [super dealloc]; 59 | } 60 | 61 | 62 | - (NSString *)getEmptyFilePath 63 | { 64 | NSArray *pathComponents = [NSArray arrayWithObjects:[[NSBundle bundleForClass:[self class]] bundlePath], @"Resources", [CurlFileTransfer emptyFilename], NULL]; 65 | 66 | return [NSString pathWithComponents:pathComponents]; 67 | } 68 | 69 | - (struct curl_slist *)headers 70 | { 71 | return headers; 72 | } 73 | 74 | - (void)appendHeader:(const char *)header 75 | { 76 | headers = curl_slist_append(headers, header); 77 | } 78 | 79 | - (void)cleanupHeaders 80 | { 81 | if (headers) 82 | { 83 | curl_slist_free_all(headers); 84 | headers = NULL; 85 | } 86 | } 87 | 88 | - (struct curl_slist *)postQuote 89 | { 90 | return postQuote; 91 | } 92 | 93 | - (void)appendPostQuote:(const char *)quote 94 | { 95 | postQuote = curl_slist_append(postQuote, quote); 96 | } 97 | 98 | - (void)cleanupPostQuotes 99 | { 100 | if (postQuote) 101 | { 102 | curl_slist_free_all(postQuote); 103 | postQuote = NULL; 104 | } 105 | } 106 | 107 | - (FILE *)getHandle 108 | { 109 | FILE *fh = NULL; 110 | 111 | if ([self isEmptyDirectory]) 112 | { 113 | fh = fopen([[self getEmptyFilePath] UTF8String], "rb"); 114 | } 115 | else 116 | { 117 | fh = fopen([localPath UTF8String], "rb"); 118 | } 119 | 120 | return fh; 121 | } 122 | 123 | 124 | - (int)getInfo:(struct stat *)info 125 | { 126 | if([self isEmptyDirectory]) 127 | { 128 | return stat([[self getEmptyFilePath] UTF8String], info); 129 | } 130 | else 131 | { 132 | return stat([localPath UTF8String], info); 133 | } 134 | } 135 | 136 | 137 | - (NSString *)description 138 | { 139 | return [NSString stringWithFormat:@" 6 | // 7 | 8 | #import 9 | #import 10 | #import "patched-curl.h" 11 | 12 | @class CurlRemoteObject; 13 | 14 | @interface CurlObject : NSObject 15 | { 16 | id delegate; 17 | 18 | SecProtocolType protocol; 19 | 20 | BOOL verbose; 21 | BOOL showProgress; 22 | 23 | NSOperationQueue *operationQueue; 24 | } 25 | 26 | @property(readwrite, assign) id delegate; 27 | @property(readwrite, assign) SecProtocolType protocol; 28 | @property(readwrite, assign) BOOL verbose; 29 | @property(readwrite, assign) BOOL showProgress; 30 | 31 | + (NSString *)libcurlVersion; 32 | 33 | - (CURL *)newHandle; 34 | 35 | @end -------------------------------------------------------------------------------- /objective-curl/src/CurlObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlObject.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlObject.h" 9 | #import "CurlRemoteObject.h" 10 | 11 | 12 | @implementation CurlObject 13 | 14 | 15 | @synthesize delegate; 16 | 17 | @synthesize protocol; 18 | 19 | @synthesize verbose; 20 | 21 | @synthesize showProgress; 22 | 23 | 24 | /* 25 | * Returns a string containing the version info of libcurl that the framework is using. 26 | * 27 | * Currently "libcurl/7.19.7 OpenSSL/0.9.7l zlib/1.2.3 libssh2/1.2.1" 28 | */ 29 | + (NSString *)libcurlVersion 30 | { 31 | return [NSString stringWithUTF8String:curl_version()]; 32 | } 33 | 34 | 35 | /* 36 | * Initialize the operation queue, and other property defaults. 37 | */ 38 | - (id)init 39 | { 40 | if (self = [super init]) 41 | { 42 | operationQueue = [[NSOperationQueue alloc] init]; 43 | } 44 | 45 | return self; 46 | } 47 | 48 | 49 | /* 50 | * Cleanup. 51 | */ 52 | - (void)dealloc 53 | { 54 | [operationQueue release], operationQueue = nil; 55 | 56 | [super dealloc]; 57 | } 58 | 59 | 60 | /* 61 | * Generates a new curl_easy_handle. 62 | * 63 | * See http://curl.haxx.se/libcurl/c/libcurl-easy.html 64 | */ 65 | - (CURL *)newHandle 66 | { 67 | CURL *handle = curl_easy_init(); 68 | 69 | curl_easy_setopt(handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER); 70 | curl_easy_setopt(handle, CURLOPT_VERBOSE, [self verbose]); 71 | curl_easy_setopt(handle, CURLOPT_NOPROGRESS, ![self showProgress]); 72 | 73 | return handle; 74 | } 75 | 76 | 77 | - (int)clientType 78 | { 79 | // Abstract 80 | 81 | return -1; 82 | } 83 | 84 | @end -------------------------------------------------------------------------------- /objective-curl/src/CurlOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlOperation.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | 9 | #import 10 | #import 11 | #import "patched-curl.h" 12 | 13 | @class CurlRemoteObject; 14 | 15 | @interface CurlOperation : NSOperation 16 | { 17 | CURL *handle; 18 | id delegate; 19 | } 20 | 21 | @property(readwrite, assign) id delegate; 22 | 23 | - (id)initWithHandle:(CURL *)aHandle delegate:(id)aDelegate; 24 | 25 | - (NSString *)getFailureDetailsForStatus:(int)status withObject:(CurlRemoteObject *)object; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /objective-curl/src/CurlOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlOperation.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | 9 | #import "CurlOperation.h" 10 | #import "CurlRemoteObject.h" 11 | 12 | 13 | @implementation CurlOperation 14 | 15 | @synthesize delegate; 16 | 17 | 18 | /* 19 | * Init with the curl handle to use, and a UploadDelegate. 20 | */ 21 | - (id)initWithHandle:(CURL *)aHandle delegate:(id)aDelegate 22 | { 23 | if (self = [super init]) 24 | { 25 | handle = aHandle; 26 | 27 | [self setDelegate:aDelegate]; 28 | } 29 | 30 | return self; 31 | } 32 | 33 | 34 | /* 35 | * Cleanup. Closes any open connections. 36 | */ 37 | - (void)dealloc 38 | { 39 | handle = NULL; 40 | 41 | curl_global_cleanup(); 42 | 43 | [super dealloc]; 44 | } 45 | 46 | 47 | 48 | /* 49 | * Return a failure status message for CURLcode. 50 | */ 51 | - (NSString *)getFailureDetailsForStatus:(int)status withObject:(CurlRemoteObject *)object 52 | { 53 | NSString *message; 54 | 55 | switch (status) 56 | { 57 | case -1: 58 | message = [NSString stringWithFormat:@"No files found to upload."]; 59 | break; 60 | 61 | case CURLE_UNSUPPORTED_PROTOCOL: 62 | message = [NSString stringWithFormat:@"Unsupported protocol %@", [object protocolPrefix]]; 63 | break; 64 | 65 | case CURLE_URL_MALFORMAT: 66 | message = [NSString stringWithFormat:@"Malformed URL %@", [object uri]]; 67 | break; 68 | 69 | case CURLE_COULDNT_RESOLVE_PROXY: 70 | message = [NSString stringWithFormat:@"Couldn't resolve proxy %@", [object hostname]]; 71 | break; 72 | 73 | case CURLE_COULDNT_RESOLVE_HOST: 74 | message = [NSString stringWithFormat:@"Couldn't resolve host %@", [object hostname]]; 75 | break; 76 | 77 | case CURLE_COULDNT_CONNECT: 78 | message = [NSString stringWithFormat:@"Couldn't connect to host %@ on port %d", [object hostname], [object port]]; 79 | break; 80 | 81 | case CURLE_FTP_WEIRD_SERVER_REPLY: 82 | message = [NSString stringWithFormat:@"Invalid response from FTP server at %@", [object hostname]]; 83 | break; 84 | 85 | case CURLE_REMOTE_ACCESS_DENIED: 86 | message = [NSString stringWithFormat:@"Failed writing to directory %@", [object path]]; 87 | break; 88 | 89 | case CURLE_REMOTE_FILE_NOT_FOUND: 90 | message = [NSString stringWithFormat:@"Remote directory not found %@:%@", [object hostname], [object path]]; 91 | break; 92 | 93 | case CURLE_PARTIAL_FILE: 94 | message = [NSString stringWithFormat:@"Incorrect number of bytes reported by server: %@", [object uri]]; 95 | break; 96 | 97 | case CURLE_UPLOAD_FAILED: 98 | message = [NSString stringWithFormat:@"Failed to start upload: %@", [object uri]]; 99 | break; 100 | 101 | case CURLE_READ_ERROR: 102 | message = [NSString stringWithFormat:@"Error reading local file."]; 103 | break; 104 | 105 | case CURLE_OUT_OF_MEMORY: 106 | message = [NSString stringWithFormat:@"cURL ran out of memory..."]; 107 | break; 108 | 109 | case CURLE_OPERATION_TIMEDOUT: 110 | message = [NSString stringWithFormat:@"Operation timed out to host %@", [object hostname]]; 111 | break; 112 | 113 | case CURLE_FILE_COULDNT_READ_FILE: 114 | message = [NSString stringWithFormat:@"Couldn't read local file, invalid permissions?"]; 115 | break; 116 | 117 | case CURLE_BAD_FUNCTION_ARGUMENT: 118 | message = [NSString stringWithFormat:@"Internal error. A function was called with a bad parameter."]; 119 | break; 120 | 121 | case CURLE_TOO_MANY_REDIRECTS: 122 | message = [NSString stringWithFormat:@"Too many redirects. %@", [object uri]]; 123 | break; 124 | 125 | case CURLE_PEER_FAILED_VERIFICATION: 126 | message = [NSString stringWithFormat:@"Host key verification failed for %@", [object hostname]]; 127 | break; 128 | 129 | case CURLE_GOT_NOTHING: 130 | message = [NSString stringWithFormat:@"No response returned from the server at %@", [object hostname]]; 131 | break; 132 | 133 | case CURLE_SEND_ERROR: 134 | message = [NSString stringWithFormat:@"Failed to send network data to %@", [object hostname]]; 135 | break; 136 | 137 | case CURLE_RECV_ERROR: 138 | message = [NSString stringWithFormat:@"Failed to receive network data from %@", [object hostname]]; 139 | break; 140 | 141 | case CURLE_BAD_CONTENT_ENCODING: 142 | message = [NSString stringWithFormat:@"Unrecognized transfer encoding sent from %@", [object hostname]]; 143 | break; 144 | 145 | case CURLE_LOGIN_DENIED: 146 | message = [NSString stringWithFormat:@"Invalid login for %@@%@", [object username], [object hostname]]; 147 | break; 148 | 149 | case CURLE_REMOTE_DISK_FULL: 150 | message = [NSString stringWithFormat:@"Remote disk is full %@", [object uri]]; 151 | break; 152 | 153 | case CURLE_FAILED_INIT: 154 | message = [NSString stringWithFormat:@"Failed to initialize %@ on %@:%d", [object protocolPrefix], [object hostname], [object port]]; 155 | break; 156 | 157 | case CURLE_QUOTE_ERROR: 158 | message = [NSString stringWithFormat:@"%@ quote command invalid", [object protocolPrefix]]; 159 | break; 160 | 161 | default: 162 | message = [NSString stringWithFormat:@"Unhandled Status Code: %d", status]; 163 | break; 164 | } 165 | 166 | return message; 167 | } 168 | 169 | 170 | @end -------------------------------------------------------------------------------- /objective-curl/src/CurlRemoteFile.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlRemoteFile.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | 10 | 11 | @interface CurlRemoteFile : NSObject 12 | { 13 | NSString *name; 14 | long size; 15 | long lastModified; 16 | BOOL isDir; 17 | BOOL isSymLink; 18 | } 19 | 20 | @property(readwrite, copy) NSString *name; 21 | @property(readwrite, assign) long size; 22 | @property(readwrite, assign) long lastModified; 23 | @property(readwrite, assign) BOOL isDir; 24 | @property(readwrite, assign) BOOL isSymLink; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /objective-curl/src/CurlRemoteFile.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlRemoteFile.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlRemoteFile.h" 9 | 10 | 11 | @implementation CurlRemoteFile 12 | 13 | /* 14 | * Filename 15 | */ 16 | @synthesize name; 17 | 18 | /* 19 | * Filesize 20 | */ 21 | @synthesize size; 22 | 23 | /* 24 | * Last Modified Timestamp 25 | */ 26 | @synthesize lastModified; 27 | 28 | /* 29 | * Is this a directory? 30 | */ 31 | @synthesize isDir; 32 | 33 | /* 34 | * Is this a symbolic link? 35 | */ 36 | @synthesize isSymLink; 37 | 38 | 39 | - (NSString *)description 40 | { 41 | return [NSString stringWithFormat:@"{RemoteFile : \"name\" => \"%@\", \"size\" => \"%lu\", \"isDir\" => \"%d\", \"lastModified\" => \"%lu\"}", name, size, isDir, lastModified]; 42 | } 43 | 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /objective-curl/src/CurlRemoteFolder.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlRemoteFolder.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlRemoteObject.h" 10 | 11 | @interface CurlRemoteFolder : CurlRemoteObject 12 | { 13 | NSArray *files; 14 | 15 | BOOL forceReload; 16 | } 17 | 18 | @property(readwrite, retain) NSArray *files; 19 | @property(readwrite, assign) BOOL forceReload; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /objective-curl/src/CurlRemoteFolder.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlRemoteFolder.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlRemoteFolder.h" 9 | 10 | 11 | @implementation CurlRemoteFolder 12 | 13 | 14 | /* 15 | * Array of CurlRemoteFile objects. 16 | */ 17 | @synthesize files; 18 | 19 | 20 | /* 21 | * Should we load this from cache 22 | */ 23 | @synthesize forceReload; 24 | 25 | 26 | - (NSString *)description 27 | { 28 | return [NSString stringWithFormat:@"<%@ path => \"%@\", totalFiles => \"%lu\"}", NSStringFromClass([self class]), path, [files count]]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /objective-curl/src/CurlRemoteObject.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlRemoteObject.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlTransferStatus.h" 10 | 11 | 12 | @interface CurlRemoteObject : NSObject 13 | { 14 | SecProtocolType protocol; 15 | NSString *protocolPrefix; 16 | NSString *hostname; 17 | int port; 18 | NSString *path; 19 | NSString *url; 20 | 21 | int clientType; 22 | 23 | NSString *username; 24 | NSString *password; 25 | 26 | BOOL usePublicKeyAuth; 27 | BOOL canUsePublicKeyAuth; 28 | NSString *privateKeyFile; 29 | NSString *publicKeyFile; 30 | 31 | CurlTransferStatus status; 32 | BOOL connected; 33 | BOOL cancelled; 34 | 35 | NSString *name; 36 | NSString *statusMessage; 37 | } 38 | 39 | 40 | @property(readwrite, assign) SecProtocolType protocol; 41 | @property(readwrite, copy) NSString *protocolPrefix; 42 | @property(readwrite, copy) NSString *hostname; 43 | @property(readwrite, assign) int port; 44 | @property(readwrite, copy) NSString *path; 45 | @property(readwrite, copy) NSString *url; 46 | 47 | @property(readwrite, assign) int clientType; 48 | 49 | @property(readwrite, copy) NSString *username; 50 | @property(readwrite, copy) NSString *password; 51 | 52 | @property(readwrite, assign) BOOL usePublicKeyAuth; 53 | @property(readwrite, assign) BOOL canUsePublicKeyAuth; 54 | @property(readwrite, copy) NSString *privateKeyFile; 55 | @property(readwrite, copy) NSString *publicKeyFile; 56 | 57 | @property(readwrite, assign) CurlTransferStatus status; 58 | @property(readwrite, assign) BOOL connected; 59 | @property(readwrite, assign) BOOL cancelled; 60 | /* 61 | * Note: These 2 properties are not used by the framework; use them as you wish. 62 | */ 63 | @property(readwrite, copy) NSString *name; 64 | @property(readwrite, copy) NSString *statusMessage; 65 | 66 | 67 | - (BOOL)hasAuthUsername; 68 | 69 | - (BOOL)hasAuthPassword; 70 | 71 | - (NSString *)uri; 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /objective-curl/src/CurlRemoteObject.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlRemoteObject.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlRemoteObject.h" 9 | 10 | 11 | @implementation CurlRemoteObject 12 | 13 | @synthesize protocol; 14 | @synthesize protocolPrefix; 15 | @synthesize hostname; 16 | @synthesize port; 17 | @synthesize path; 18 | @synthesize url; 19 | 20 | @synthesize clientType; 21 | 22 | @synthesize username; 23 | @synthesize password; 24 | 25 | @synthesize usePublicKeyAuth; 26 | @synthesize canUsePublicKeyAuth; 27 | @synthesize privateKeyFile; 28 | @synthesize publicKeyFile; 29 | 30 | @synthesize status; 31 | @synthesize cancelled; 32 | @synthesize connected; 33 | 34 | @synthesize name; 35 | @synthesize statusMessage; 36 | 37 | 38 | - (void)dealloc 39 | { 40 | [protocolPrefix release], protocolPrefix = nil; 41 | [hostname release], hostname = nil; 42 | [username release], username = nil; 43 | [password release], password = nil; 44 | [privateKeyFile release], privateKeyFile = nil; 45 | [publicKeyFile release], publicKeyFile = nil; 46 | [path release], path = nil; 47 | [url release], url = nil; 48 | [statusMessage release], statusMessage = nil; 49 | 50 | [super dealloc]; 51 | } 52 | 53 | 54 | /* 55 | * Convenience function... do we have a username set for auth? 56 | */ 57 | - (BOOL)hasAuthUsername 58 | { 59 | return (username != NULL && ![username isEqualToString:@""]); 60 | } 61 | 62 | 63 | /* 64 | * Convenience function... do we have a password set for auth? 65 | */ 66 | - (BOOL)hasAuthPassword 67 | { 68 | return (password != NULL && ![password isEqualToString:@""]); 69 | } 70 | 71 | 72 | - (NSString *)uri 73 | { 74 | return [NSString stringWithFormat:@"%@://%@@%@:%d/%@", protocolPrefix, username, hostname, port, path]; 75 | } 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlS3.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlFTP.h" 10 | #import "CurlClient.h" 11 | 12 | 13 | @interface CurlS3 : CurlFTP 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlS3.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlS3.h" 9 | #import "CurlClientType.h" 10 | #import "CurlS3ListOperation.h" 11 | #import "CurlS3UploadOperation.h" 12 | #import "CurlUpload.h" 13 | #import "NSString+PathExtras.h" 14 | 15 | 16 | @implementation CurlS3 17 | 18 | 19 | - (id)init 20 | { 21 | if (self = [super init]) 22 | { 23 | [self setProtocol:kSecProtocolTypeHTTPS]; 24 | } 25 | 26 | return self; 27 | } 28 | 29 | 30 | - (NSString *)protocolPrefix 31 | { 32 | return @"https"; 33 | } 34 | 35 | 36 | - (int)defaultPort 37 | { 38 | return 443; 39 | } 40 | 41 | 42 | - (int)clientType 43 | { 44 | return CURL_CLIENT_S3; 45 | } 46 | 47 | 48 | - (void)upload:(CurlUpload *)record 49 | { 50 | [record setProgress:0]; 51 | [record setStatus:CURL_TRANSFER_STATUS_QUEUED]; 52 | [record setConnected:NO]; 53 | [record setCancelled:NO]; 54 | 55 | CurlS3ListOperation *listOperation = [[CurlS3ListOperation alloc] initWithHandle:[self newHandle] delegate:delegate]; 56 | 57 | CurlS3UploadOperation *uploadOperation = [[CurlS3UploadOperation alloc] initWithHandle:[self newHandle] delegate:delegate]; 58 | 59 | [listOperation setRequest:record]; 60 | [uploadOperation setUpload:record]; 61 | [uploadOperation addDependency:listOperation]; 62 | 63 | [operationQueue addOperation:listOperation]; 64 | [operationQueue addOperation:uploadOperation]; 65 | 66 | [listOperation release]; 67 | [uploadOperation release]; 68 | } 69 | 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3DateUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // S3DateUtil.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | 10 | 11 | @interface CurlS3DateUtil : NSObject 12 | 13 | + (NSString *)dateStringForNow; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3DateUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // S3DateUtil.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlS3DateUtil.h" 9 | 10 | 11 | @implementation CurlS3DateUtil 12 | 13 | + (NSString *)dateStringForNow 14 | { 15 | // Construct a date string in the format that S3 expects 16 | 17 | NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; 18 | 19 | [dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss zzzz"]; 20 | 21 | return [dateFormatter stringFromDate:[NSDate date]]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3ErrorCodes.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlS3ErrorCodes.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | const NSString * S3AccessDenied = @"AccessDenied"; 9 | const NSString * S3AccountProblem = @"AccountProblem"; 10 | const NSString * S3AmbiguousGrantByEmailAddress = @"AmbiguousGrantByEmailAddress"; 11 | const NSString * S3BadDigest = @"BadDigest"; 12 | const NSString * S3BucketAlreadyExists = @"BucketAlreadyExists"; 13 | const NSString * S3BucketAlreadyOwnedByYou = @"BucketAlreadyOwnedByYou"; 14 | const NSString * S3BucketNotEmpty = @"BucketNotEmpty"; 15 | const NSString * S3CredentialsNotSupported = @"CredentialsNotSupported"; 16 | const NSString * S3CrossLocationLoggingProhibited = @"CrossLocationLoggingProhibited"; 17 | const NSString * S3EntityTooSmall = @"EntityTooSmall"; 18 | const NSString * S3EntityTooLarge = @"EntityTooLarge"; 19 | const NSString * S3ExpiredToken = @"ExpiredToken"; 20 | const NSString * S3IncompleteBody = @"IncompleteBody"; 21 | const NSString * S3IncorrectNumberOfFilesInPostRequest = @"IncorrectNumberOfFilesInPostRequest"; 22 | const NSString * S3InlineDataTooLarge = @"InlineDataTooLarge"; 23 | const NSString * S3InternalError = @"InternalError"; 24 | const NSString * S3InvalidAccessKeyId = @"InvalidAccessKeyId"; 25 | const NSString * S3InvalidAddressingHeader = @"InvalidAddressingHeader"; 26 | const NSString * S3InvalidArgument = @"InvalidArgument"; 27 | const NSString * S3InvalidBucketName = @"InvalidBucketName"; 28 | const NSString * S3InvalidDigest = @"InvalidDigest"; 29 | const NSString * S3InvalidLocationConstraint = @"InvalidLocationConstraint"; 30 | const NSString * S3InvalidPayer = @"InvalidPayer"; 31 | const NSString * S3InvalidPolicyDocument = @"InvalidPolicyDocument"; 32 | const NSString * S3InvalidRange = @"InvalidRange"; 33 | const NSString * S3InvalidSecurity = @"InvalidSecurity"; 34 | const NSString * S3InvalidSOAPRequest = @"InvalidSOAPRequest"; 35 | const NSString * S3InvalidStorageClass = @"InvalidStorageClass"; 36 | const NSString * S3InvalidTargetBucketForLogging = @"InvalidTargetBucketForLogging"; 37 | const NSString * S3InvalidToken = @"InvalidToken"; 38 | const NSString * S3InvalidURI = @"InvalidURI"; 39 | const NSString * S3KeyTooLong = @"KeyTooLong"; 40 | const NSString * S3MalformedACLError = @"MalformedACLError"; 41 | const NSString * S3MalformedPOSTRequest = @"MalformedPOSTRequest"; 42 | const NSString * S3MalformedXML = @"MalformedXML"; 43 | const NSString * S3MaxMessageLengthExceeded = @"MaxMessageLengthExceeded"; 44 | const NSString * S3MaxPostPreDataLengthExceededError = @"MaxPostPreDataLengthExceededError"; 45 | const NSString * S3MetadataTooLarge = @"MetadataTooLarge"; 46 | const NSString * S3MethodNotAllowed = @"MethodNotAllowed"; 47 | const NSString * S3MissingAttachment = @"MissingAttachment"; 48 | const NSString * S3MissingContentLength = @"MissingContentLength"; 49 | const NSString * S3MissingRequestBodyError = @"MissingRequestBodyError"; 50 | const NSString * S3MissingSecurityElement = @"MissingSecurityElement"; 51 | const NSString * S3MissingSecurityHeader = @"MissingSecurityHeader"; 52 | const NSString * S3NoLoggingStatusForKey = @"NoLoggingStatusForKey"; 53 | const NSString * S3NoSuchBucket = @"NoSuchBucket"; 54 | const NSString * S3NoSuchKey = @"NoSuchKey"; 55 | const NSString * S3NotImplemented = @"NotImplemented"; 56 | const NSString * S3NotSignedUp = @"NotSignedUp"; 57 | const NSString * S3OperationAborted = @"OperationAborted"; 58 | const NSString * S3PermanentRedirect = @"PermanentRedirect"; 59 | const NSString * S3PreconditionFailed = @"PreconditionFailed"; 60 | const NSString * S3Redirect = @"Redirect"; 61 | const NSString * S3RequestIsNotMultiPartContent = @"RequestIsNotMultiPartContent"; 62 | const NSString * S3RequestTimeout = @"RequestTimeout"; 63 | const NSString * S3RequestTimeTooSkewed = @"RequestTimeTooSkewed"; 64 | const NSString * S3RequestTorrentOfBucketError = @"RequestTorrentOfBucketError"; 65 | const NSString * S3SignatureDoesNotMatch = @"SignatureDoesNotMatch"; 66 | const NSString * S3SlowDown = @"SlowDown"; 67 | const NSString * S3TemporaryRedirect = @"TemporaryRedirect"; 68 | const NSString * S3TokenRefreshRequired = @"TokenRefreshRequired"; 69 | const NSString * S3TooManyBuckets = @"TooManyBuckets"; 70 | const NSString * S3UnexpectedContent = @"UnexpectedContent"; 71 | const NSString * S3UnresolvableGrantByEmailAddress = @"UnresolvableGrantByEmailAddress"; 72 | const NSString * S3UserKeyMustBeSpecified = @"UserKeyMustBeSpecified"; 73 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3ErrorParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // S3ErrorParser.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | 10 | 11 | const NSString * S3ErrorCodeKey; 12 | 13 | const NSString * S3ErrorMessageKey; 14 | 15 | 16 | @interface CurlS3ErrorParser : NSObject 17 | 18 | + (NSDictionary *)parseErrorDetails:(NSString *)resp; 19 | 20 | + (int)transferStatusForErrorCode:(NSString *)code; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3ErrorParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // S3ErrorParser.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlS3ErrorParser.h" 9 | #import "CurlS3ErrorCodes.h" 10 | #import "CurlTransferStatus.h" 11 | 12 | const NSString * S3ErrorCodeKey = @"S3ErrorCode"; 13 | const NSString * S3ErrorMessageKey = @"S3ErrorMessage"; 14 | 15 | @implementation CurlS3ErrorParser 16 | 17 | + (NSDictionary *)parseErrorDetails:(NSString *)resp { 18 | 19 | NSString *s3ErrorCode = @"Unknown"; 20 | NSString *s3ErrorMessage = @"Amazon S3 Error"; 21 | NSError *err = nil; 22 | NSXMLDocument *xml = [[NSXMLDocument alloc] initWithXMLString:resp 23 | options:NSXMLDocumentTidyXML 24 | error:&err]; 25 | 26 | if (!err) { 27 | NSXMLNode *msgNode, *codeNode = nil; 28 | 29 | if ([xml nodesForXPath:@"./Error/Code" error:&err] && !err) { 30 | codeNode = [[xml nodesForXPath:@"./Error/Code" error:nil] objectAtIndex:0]; 31 | msgNode = [[xml nodesForXPath:@"./Error/Message" error:nil] objectAtIndex:0]; 32 | } 33 | else 34 | { 35 | return nil; 36 | } 37 | 38 | s3ErrorCode = [codeNode stringValue]; 39 | s3ErrorMessage = [msgNode stringValue]; 40 | } 41 | else { 42 | NSLog(@"Error parsing S3 Response: %@", [err description]); 43 | } 44 | 45 | [xml release]; 46 | 47 | return [NSDictionary dictionaryWithObjectsAndKeys: s3ErrorCode, 48 | S3ErrorCodeKey, 49 | s3ErrorMessage, 50 | S3ErrorMessageKey, 51 | NULL]; 52 | } 53 | 54 | 55 | + (int)transferStatusForErrorCode:(NSString *)code 56 | { 57 | if ([code isEqualToString:(NSString *)S3SignatureDoesNotMatch] || 58 | [code isEqualToString:(NSString *)S3InvalidAccessKeyId] || 59 | [code isEqualToString:(NSString *)S3AccessDenied]) { 60 | return CURL_TRANSFER_STATUS_LOGIN_DENIED; 61 | } 62 | 63 | return CURL_TRANSFER_STATUS_FAILED; 64 | } 65 | 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3ListOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // S3ListOperation.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlOperation.h" 10 | 11 | 12 | struct ResultStruct { 13 | char *buffer; 14 | size_t size; 15 | }; 16 | 17 | 18 | @class CurlRemoteObject; 19 | 20 | 21 | @interface CurlS3ListOperation : CurlOperation { 22 | 23 | CurlRemoteObject *request; 24 | } 25 | 26 | 27 | @property(readwrite, retain) CurlRemoteObject *request; 28 | 29 | 30 | static size_t handleS3BucketListProgress(CurlS3ListOperation *operation, int connected, double dltotal, double dlnow, double ultotal, double ulnow); 31 | 32 | static size_t handleS3BucketList(void *ptr, size_t size, size_t nmemb, void *data); 33 | 34 | 35 | - (void)setupCurl; 36 | 37 | - (void)handleS3BucketListResult:(CURLcode)result body:(NSString *)xml; 38 | 39 | - (void)handleS3BucketListFailed:(CURLcode)result error:(NSDictionary *)s3error; 40 | 41 | - (void)performDelegateSelector:(SEL)aSelector; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3ListOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // S3ListOperation.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "NSString+S3.h" 9 | 10 | #import "CurlS3ListOperation.h" 11 | #import "CurlS3ErrorParser.h" 12 | #import "CurlS3DateUtil.h" 13 | #import "CurlRemoteObject.h" 14 | 15 | @implementation CurlS3ListOperation 16 | 17 | @synthesize request; 18 | 19 | static size_t handleS3BucketList(void *ptr, size_t size, size_t nmemb, void *data) { 20 | size_t realsize = size * nmemb; 21 | 22 | struct ResultStruct *res = (struct ResultStruct *)data; 23 | 24 | res->buffer = ptr ? realloc(res->buffer, res->size + realsize + 1) : malloc(res->size + realsize + 1); 25 | 26 | if (res->buffer) { 27 | memcpy(&(res->buffer[res->size]), ptr, realsize); 28 | res->size += realsize; 29 | res->buffer[res->size] = 0; 30 | } 31 | 32 | return realsize; 33 | } 34 | 35 | 36 | 37 | static size_t handleS3BucketListProgress(CurlS3ListOperation *operation, int connected, double dltotal, double dlnow, double ultotal, double ulnow) 38 | { 39 | CurlRemoteObject *request = [operation request]; 40 | 41 | if (!connected) 42 | { 43 | if ([request status] != CURL_TRANSFER_STATUS_CONNECTING) 44 | { 45 | // Connecting ... 46 | [request setConnected:NO]; 47 | [request setStatus:CURL_TRANSFER_STATUS_CONNECTING]; 48 | 49 | // Notify the delegate 50 | [operation performDelegateSelector:@selector(curlIsConnecting:)]; 51 | } 52 | } 53 | else 54 | { 55 | if (![request connected]) 56 | { 57 | // We have a connection. 58 | [request setConnected:YES]; 59 | [request setStatus:CURL_TRANSFER_STATUS_CONNECTED]; 60 | 61 | // Notify the delegate 62 | [operation performDelegateSelector:@selector(curlDidConnect:)]; 63 | } 64 | } 65 | 66 | return ([request cancelled] || [request status] == CURL_TRANSFER_STATUS_FAILED); 67 | } 68 | 69 | 70 | 71 | - (void)setupCurl 72 | { 73 | curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); 74 | curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, handleS3BucketList); 75 | curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, handleS3BucketListProgress); 76 | curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, self); 77 | } 78 | 79 | 80 | 81 | - (void)main 82 | { 83 | if ([self isCancelled]) return; 84 | 85 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 86 | 87 | [self setupCurl]; 88 | 89 | NSString *url = [NSString stringWithFormat:@"%@://%@:%d/%@", 90 | [request protocolPrefix], [request hostname], [request port], [request path]]; 91 | 92 | struct ResultStruct resp; 93 | resp.buffer = NULL; 94 | resp.size = 0; 95 | 96 | curl_easy_setopt(handle, CURLOPT_URL, [url UTF8String]); 97 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, &resp); 98 | 99 | // Setup S3 Headers 100 | NSString *accessKey = [request username]; 101 | NSString *secretKey = [request password]; 102 | NSString *date = [CurlS3DateUtil dateStringForNow]; 103 | NSString *resource = [NSString stringWithFormat:@"/%@", [request path]]; 104 | 105 | // Details of the request to be signed 106 | NSString *stringToSign = [NSString stringWithFormat:@"GET\n\n\n%@\n%@", date, resource]; 107 | 108 | // Construct the S3 authorization header 109 | NSString *authString = [NSString stringWithFormat:@"AWS %@:%@", 110 | accessKey, [stringToSign signS3PutRequestWithKey:secretKey]]; 111 | 112 | struct curl_slist *headers = NULL; 113 | 114 | // Set the Request Headers 115 | headers = curl_slist_append(headers, "User-Agent:"); 116 | headers = curl_slist_append(headers, "Accept:"); 117 | headers = curl_slist_append(headers, "Expect:"); 118 | headers = curl_slist_append(headers, [[NSString stringWithFormat:@"Date: %@", date] UTF8String]); 119 | headers = curl_slist_append(headers, [[NSString stringWithFormat:@"Authorization: %@", authString] UTF8String]); 120 | 121 | curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); 122 | 123 | int result = -1; 124 | 125 | result = curl_easy_perform(handle); 126 | 127 | [self handleS3BucketListResult:result body:[NSString stringWithUTF8String:resp.buffer]]; 128 | 129 | if (resp.buffer) { 130 | free(resp.buffer); 131 | } 132 | 133 | [pool drain]; 134 | } 135 | 136 | 137 | 138 | - (void)handleS3BucketListResult:(CURLcode)result body:(NSString *)xml 139 | { 140 | NSDictionary *error = [CurlS3ErrorParser parseErrorDetails:xml]; 141 | 142 | if (!error && result == CURLE_OK) { 143 | 144 | // [request setStatus:TRANSFER_STATUS_COMPLETE]; 145 | 146 | } 147 | else { 148 | 149 | [self handleS3BucketListFailed:result error:error]; 150 | } 151 | } 152 | 153 | 154 | 155 | - (void)handleS3BucketListFailed:(CURLcode)result error:(NSDictionary *)s3error 156 | { 157 | // The upload operation failed. 158 | int status; 159 | 160 | if (s3error) { 161 | 162 | NSString *s3code = [s3error objectForKey:S3ErrorCodeKey]; 163 | NSString *s3message = [s3error objectForKey:S3ErrorMessageKey]; 164 | 165 | [request setStatus:[CurlS3ErrorParser transferStatusForErrorCode:s3code]]; 166 | 167 | NSString *message = ([request status] == CURL_TRANSFER_STATUS_LOGIN_DENIED) ? 168 | [self getFailureDetailsForStatus:CURLE_LOGIN_DENIED withObject:request] : 169 | [NSString stringWithFormat:@"%@:%@", s3code, s3message]; 170 | 171 | [request setStatusMessage:message]; 172 | } 173 | else 174 | { 175 | switch (result) 176 | { 177 | // Auth Failure 178 | case CURLE_LOGIN_DENIED: 179 | status = CURL_TRANSFER_STATUS_LOGIN_DENIED; 180 | break; 181 | 182 | // General Failure 183 | default: 184 | status = CURL_TRANSFER_STATUS_FAILED; 185 | break; 186 | } 187 | 188 | [request setStatus:status]; 189 | [request setStatusMessage:[self getFailureDetailsForStatus:result withObject:request]]; 190 | 191 | } 192 | 193 | [self cancel]; 194 | } 195 | 196 | 197 | 198 | - (void)performDelegateSelector:(SEL)aSelector 199 | { 200 | if (delegate && [delegate respondsToSelector:aSelector]) 201 | { 202 | [delegate performSelectorOnMainThread:aSelector withObject:request waitUntilDone:NO]; 203 | } 204 | } 205 | 206 | 207 | @end 208 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3UploadOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // S3UploadOperation.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlUploadOperation.h" 10 | 11 | 12 | @interface CurlS3UploadOperation : CurlUploadOperation { 13 | 14 | NSString *errorCode; 15 | NSString *errorMessage; 16 | 17 | } 18 | 19 | @property(readwrite, copy) NSString *errorCode; 20 | @property(readwrite, copy) NSString *errorMessage; 21 | 22 | static size_t writeFunction(void *ptr, size_t size, size_t nmemb, CurlS3UploadOperation *op); 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /objective-curl/src/CurlS3UploadOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // S3UploadOperation.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "NSString+S3.h" 9 | #import "NSString+PathExtras.h" 10 | #import "NSString+URLEncoding.h" 11 | #import "NSFileManager+MimeType.h" 12 | #import "NSObject+DDExtensions.h" 13 | 14 | #import "CurlS3UploadOperation.h" 15 | #import "CurlUpload.h" 16 | #import "CurlUploadDelegate.h" 17 | #import "CurlFileTransfer.h" 18 | #import "CurlS3ErrorParser.h" 19 | #import "CurlS3DateUtil.h" 20 | 21 | @implementation CurlS3UploadOperation 22 | 23 | 24 | @synthesize errorCode; 25 | 26 | @synthesize errorMessage; 27 | 28 | 29 | 30 | /* 31 | * If we got a response body from PUT request then we handle it as an error and bail. 32 | */ 33 | static size_t writeFunction(void *ptr, size_t size, size_t nmemb, CurlS3UploadOperation *op) 34 | { 35 | NSString *resp = [NSString stringWithUTF8String:(char *)ptr]; 36 | 37 | NSDictionary *err = [CurlS3ErrorParser parseErrorDetails:resp]; 38 | 39 | [op setErrorCode:[err objectForKey:S3ErrorCodeKey]]; 40 | [op setErrorMessage:[err objectForKey:S3ErrorMessageKey]]; 41 | 42 | return 0; 43 | } 44 | 45 | 46 | /* 47 | * Set curl options for Amazon S3. 48 | */ 49 | - (void)setProtocolSpecificOptions 50 | { 51 | curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); 52 | curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeFunction); 53 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, self); 54 | curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); 55 | curl_easy_setopt(handle, CURLOPT_MAXREDIRS, 10); 56 | curl_easy_setopt(handle, CURLOPT_NETRC, CURL_NETRC_IGNORED); 57 | } 58 | 59 | 60 | /* 61 | * Set S3 Auth/HTTP Headers for the current file being uploaded. 62 | * 63 | */ 64 | - (void)setFileSpecificOptions:(CurlFileTransfer *)file 65 | { 66 | // These act the same as username and password 67 | NSString *accessKey = [upload username]; 68 | NSString *secretKey = [upload password]; 69 | 70 | NSString *date = [CurlS3DateUtil dateStringForNow]; 71 | 72 | NSString *resource = [[NSString stringWithFormat:@"/%@", [[file remotePath] stringByRemovingTildePrefix]] encodedURLString]; 73 | 74 | // Get the content type of the file we're uploading 75 | NSString *contentType = [NSFileManager mimeTypeForFileAtPath:[file localPath]]; 76 | 77 | // TODO - don't hardcode this 78 | NSString *acl = @"x-amz-acl:public-read"; 79 | 80 | // Details of the request to be signed 81 | NSString *stringToSign = [NSString stringWithFormat:@"PUT\n\n%@\n%@\n%@\n%@", contentType, date, acl, resource]; 82 | 83 | // Construct the S3 authorization header 84 | NSString *authString = [NSString stringWithFormat:@"AWS %@:%@", 85 | accessKey, [stringToSign signS3PutRequestWithKey:secretKey]]; 86 | 87 | struct curl_slist *headers = NULL; 88 | 89 | // Set the Request Headers 90 | headers = curl_slist_append(headers, "User-Agent:"); 91 | headers = curl_slist_append(headers, "Accept:"); 92 | headers = curl_slist_append(headers, "Expect:"); 93 | headers = curl_slist_append(headers, [acl UTF8String]); 94 | headers = curl_slist_append(headers, [[NSString stringWithFormat:@"Content-Type: %@", contentType] UTF8String]); 95 | headers = curl_slist_append(headers, [[NSString stringWithFormat:@"Date: %@", date] UTF8String]); 96 | headers = curl_slist_append(headers, [[NSString stringWithFormat:@"Authorization: %@", authString] UTF8String]); 97 | 98 | curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); 99 | 100 | // TODO - figure out a way to free the headers 101 | } 102 | 103 | 104 | 105 | /* 106 | * Overridden to handle Amazon S3 Specific Failures. 107 | * 108 | */ 109 | - (void)handleUploadFailed:(CURLcode)result 110 | { 111 | // The upload operation failed. 112 | int status; 113 | switch (result) 114 | { 115 | // Aborted from the write_func? That means Amazon S3 threw an error... 116 | case CURLE_WRITE_ERROR: 117 | status = [CurlS3ErrorParser transferStatusForErrorCode:errorCode]; 118 | break; 119 | 120 | // Otherwise, process as a normal error. 121 | default: 122 | return [super handleUploadFailed:result]; 123 | } 124 | 125 | [upload setStatus:status]; 126 | 127 | NSString *message = (status == CURL_TRANSFER_STATUS_LOGIN_DENIED) ? 128 | [self getFailureDetailsForStatus:CURLE_LOGIN_DENIED withObject:upload] : 129 | [NSString stringWithFormat:@"%@:%@", errorCode, errorMessage]; 130 | 131 | if (delegate && [delegate respondsToSelector:@selector(uploadDidFail:message:)]) 132 | { 133 | [[delegate invokeOnMainThread] uploadDidFail:upload message:message]; 134 | } 135 | } 136 | 137 | 138 | - (NSString *)urlForTransfer:(CurlFileTransfer *)file 139 | { 140 | NSString *filePath = [[file remotePath] stringByRemovingTildePrefix]; 141 | 142 | NSString *path = [[NSString stringWithFormat:@"%@:%d", [upload hostname], [upload port]] stringByAppendingPathComponent:filePath]; 143 | 144 | NSString *url = [NSString stringWithFormat:@"%@://%@", [upload protocolPrefix], [path encodedURLString]]; 145 | 146 | return url; 147 | } 148 | 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /objective-curl/src/CurlSCP.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlSCP.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlSFTP.h" 10 | 11 | @interface CurlSCP : CurlSFTP 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /objective-curl/src/CurlSCP.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlSCP.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlSCP.h" 9 | 10 | @implementation CurlSCP 11 | 12 | - (NSString *)protocolPrefix 13 | { 14 | return @"scp"; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /objective-curl/src/CurlSFTP.h: -------------------------------------------------------------------------------- 1 | // 2 | // CurlSFTP.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlFTP.h" 10 | #import "CurlClient.h" 11 | 12 | extern int const DEFAULT_SFTP_PORT; 13 | 14 | extern NSString * const DEFAULT_KNOWN_HOSTS; 15 | 16 | extern NSString * const SFTP_PROTOCOL_PREFIX; 17 | 18 | 19 | @interface CurlSFTP : CurlFTP 20 | { 21 | NSString *knownHostsFile; 22 | } 23 | 24 | @property(readwrite, copy) NSString *knownHostsFile; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /objective-curl/src/CurlSFTP.m: -------------------------------------------------------------------------------- 1 | // 2 | // CurlSFTP.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "NSString+PathExtras.h" 9 | 10 | #import "CurlSFTP.h" 11 | #import "CurlClientType.h" 12 | #import "CurlUpload.h" 13 | #import "CurlSSHUploadOperation.h" 14 | 15 | NSString * const DEFAULT_KNOWN_HOSTS = @"~/.ssh/known_hosts"; 16 | 17 | 18 | @implementation CurlSFTP 19 | 20 | 21 | @synthesize knownHostsFile; 22 | 23 | /* 24 | * Initializes the class instance for performing FTP uploads. If you don't use this method then you will have to manually set some or all 25 | * of these options before doing any uploads 26 | */ 27 | - (id)init 28 | { 29 | if (self = [super init]) 30 | { 31 | [self setProtocol:kSecProtocolTypeSSH]; 32 | 33 | [self setKnownHostsFile:[DEFAULT_KNOWN_HOSTS stringByExpandingTildeInPath]]; 34 | } 35 | 36 | return self; 37 | } 38 | 39 | 40 | /* 41 | * Cleanup 42 | */ 43 | - (void)dealloc 44 | { 45 | [knownHostsFile release], knownHostsFile = nil; 46 | 47 | [super dealloc]; 48 | } 49 | 50 | 51 | /* 52 | * Generates a new curl_easy_handle with SFTP-specific options set. 53 | * 54 | * See http://curl.haxx.se/libcurl/c/libcurl-easy.html 55 | */ 56 | - (CURL *)newHandle 57 | { 58 | CURL *handle = [super newHandle]; 59 | 60 | curl_easy_setopt(handle, CURLOPT_SSH_KNOWNHOSTS, [knownHostsFile UTF8String]); 61 | 62 | return handle; 63 | } 64 | 65 | 66 | - (NSString *)protocolPrefix 67 | { 68 | return @"sftp"; 69 | } 70 | 71 | 72 | - (int)defaultPort 73 | { 74 | return 22; 75 | } 76 | 77 | 78 | - (int)clientType 79 | { 80 | return CURL_CLIENT_SFTP; 81 | } 82 | 83 | 84 | - (void)upload:(CurlUpload *)record 85 | { 86 | CurlSSHUploadOperation *op = [[CurlSSHUploadOperation alloc] initWithHandle:[self newHandle] delegate:delegate]; 87 | 88 | [record setCanUsePublicKeyAuth:YES]; 89 | [record setProgress:0]; 90 | [record setStatus:CURL_TRANSFER_STATUS_QUEUED]; 91 | [record setConnected:NO]; 92 | [record setCancelled:NO]; 93 | 94 | [op setUpload:record]; 95 | [operationQueue addOperation:op]; 96 | [op release]; 97 | } 98 | 99 | 100 | /* 101 | * Returns an array of files that exist in a remote directory. Will use items in the directoryListCache if they exist. Uses 102 | * the default SFTP port. 103 | */ 104 | - (CurlRemoteFolder *)listRemoteDirectory:(NSString *)directory onHost:(NSString *)host 105 | { 106 | return [self listRemoteDirectory:directory 107 | onHost:host 108 | forceReload:NO 109 | port:[self defaultPort]]; 110 | } 111 | 112 | 113 | /* 114 | * Returns an array of files that exist in a remote directory. The forceReload flag will bypass using the directoryListCache and 115 | * always return a fresh listing from the specified server. Uses the default SFTP port. 116 | */ 117 | - (CurlRemoteFolder *)listRemoteDirectory:(NSString *)directory onHost:(NSString *)host forceReload:(BOOL)reload 118 | { 119 | return [self listRemoteDirectory:directory 120 | onHost:host 121 | forceReload:reload 122 | port:[self defaultPort]]; 123 | } 124 | 125 | 126 | @end -------------------------------------------------------------------------------- /objective-curl/src/CurlSSHUploadOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // SSHUploadOperation.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlUploadOperation.h" 10 | 11 | @class CurlUpload; 12 | 13 | extern NSString * const SFTP_PROTOCOL_PREFIX; 14 | 15 | @interface CurlSSHUploadOperation : CurlUploadOperation 16 | 17 | static int hostKeyCallback(CURL *curl, const struct curl_khkey *knownKey, const struct curl_khkey *foundKey, enum curl_khmatch type, CurlSSHUploadOperation *operation); 18 | 19 | - (int)acceptUnknownHostFingerprint:(NSString *)fingerprint forUpload:(CurlUpload *)record; 20 | - (int)acceptMismatchedHostFingerprint:(NSString *)fingerprint forUpload:(CurlUpload *)record; 21 | 22 | - (void)showUnknownKeyWarningForHost:(NSString *)hostname; 23 | - (void)showMismatchKeyWarningForHost:(NSString *)hostname; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /objective-curl/src/CurlSSHUploadOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // SSHUploadOperation.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlSSHUploadOperation.h" 9 | #import "CurlUpload.h" 10 | #import "CurlFileTransfer.h" 11 | #import "NSString+MD5.h" 12 | #import "NSString+PathExtras.h" 13 | #import "NSObject+DDExtensions.h" 14 | 15 | 16 | @implementation CurlSSHUploadOperation 17 | 18 | 19 | /* 20 | * Invoked by curl when the known_host key matching is done. Returns a curl_khstat that determines how to proceed. 21 | * 22 | * See http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTSSHKEYFUNCTION 23 | */ 24 | static int hostKeyCallback(CURL *curl, const struct curl_khkey *knownKey, const struct curl_khkey *foundKey, enum curl_khmatch type, CurlSSHUploadOperation *operation) 25 | { 26 | int result = -1; 27 | 28 | CurlUpload *transfer = [operation upload]; 29 | 30 | NSString *receivedKey = [NSString formattedMD5:foundKey->key length:foundKey->len]; 31 | 32 | switch (type) 33 | { 34 | case CURLKHMATCH_OK: 35 | result = CURLKHSTAT_FINE; 36 | break; 37 | 38 | case CURLKHMATCH_MISSING: 39 | result = [operation acceptUnknownHostFingerprint:receivedKey forUpload:transfer]; 40 | break; 41 | 42 | case CURLKHMATCH_MISMATCH: 43 | result = [operation acceptMismatchedHostFingerprint:receivedKey forUpload:transfer]; 44 | break; 45 | 46 | default: 47 | result = CURLKHSTAT_REJECT; 48 | NSLog(@"Unknown curl_khmatch type: %d", type); 49 | break; 50 | } 51 | 52 | return result; 53 | } 54 | 55 | 56 | - (void)setProtocolSpecificOptions 57 | { 58 | [super setProtocolSpecificOptions]; 59 | 60 | curl_easy_setopt(handle, CURLOPT_SSH_KEYFUNCTION, hostKeyCallback); 61 | curl_easy_setopt(handle, CURLOPT_SSH_KEYDATA, self); 62 | 63 | if ([upload usePublicKeyAuth]) 64 | { 65 | curl_easy_setopt(handle, CURLOPT_SSH_PRIVATE_KEYFILE, [[upload privateKeyFile] UTF8String]); 66 | curl_easy_setopt(handle, CURLOPT_SSH_PUBLIC_KEYFILE, [[upload publicKeyFile] UTF8String]); 67 | curl_easy_setopt(handle, CURLOPT_KEYPASSWD, [[upload password] UTF8String]); 68 | } 69 | } 70 | 71 | 72 | - (void)setFileSpecificOptions:(CurlFileTransfer *)file 73 | { 74 | if ([file isEmptyDirectory]) 75 | { 76 | const char *removeTempFile = [[NSString stringWithFormat:@"RM \"%@\"", [[file remotePath] stringByRemovingTildePrefix]] UTF8String]; 77 | 78 | [file appendPostQuote:removeTempFile]; 79 | } 80 | 81 | curl_easy_setopt(handle, CURLOPT_POSTQUOTE, [file postQuote]); 82 | } 83 | 84 | 85 | - (NSString *)urlForTransfer:(CurlFileTransfer *)file 86 | { 87 | NSString *filePath = [[file remotePath] stringByRemovingTildePrefix]; 88 | 89 | NSString *path = [[NSString stringWithFormat:@"%@:%d", [upload hostname], [upload port]] stringByAppendingPathComponent:[filePath stringByAddingTildePrefix]]; 90 | 91 | NSString *url = [NSString stringWithFormat:@"%@://%@", [upload protocolPrefix], path]; 92 | 93 | return url; 94 | } 95 | 96 | 97 | /* 98 | * How should we handle the unknown host key fingerprint. If a delegate implementation exists then query 99 | * the delegate for an answer. Otherwise proceed. 100 | * 101 | */ 102 | - (int)acceptUnknownHostFingerprint:(NSString *)fingerprint forUpload:(CurlUpload *)record 103 | { 104 | int answer = CURLKHSTAT_DEFER; 105 | 106 | if (delegate && [delegate respondsToSelector:@selector(acceptUnknownHostFingerprint:forUpload:)]) 107 | { 108 | answer = [[delegate invokeOnMainThreadAndWaitUntilDone:YES] 109 | acceptUnknownHostFingerprint:fingerprint forUpload:record]; 110 | } 111 | else 112 | { 113 | [self showUnknownKeyWarningForHost:[record hostname]]; 114 | } 115 | 116 | return answer; 117 | } 118 | 119 | 120 | /* 121 | * How should we handle the mismatched host key fingerprint. If a delegate implementation exists then query 122 | * the delegate for an answer. Otherwise proceed. 123 | * 124 | */ 125 | - (int)acceptMismatchedHostFingerprint:(NSString *)fingerprint forUpload:(CurlUpload *)record 126 | { 127 | int answer = CURLKHSTAT_DEFER; 128 | 129 | if (delegate && [delegate respondsToSelector:@selector(acceptMismatchedHostFingerprint:forUpload:)]) 130 | { 131 | answer = [[delegate invokeOnMainThreadAndWaitUntilDone:YES] 132 | acceptMismatchedHostFingerprint:fingerprint forUpload:record]; 133 | } 134 | else 135 | { 136 | [self showMismatchKeyWarningForHost:[record hostname]]; 137 | } 138 | 139 | return answer; 140 | } 141 | 142 | 143 | /* 144 | * Log warning for unknown hostKey. 145 | */ 146 | - (void)showUnknownKeyWarningForHost:(NSString *)hostname 147 | { 148 | NSLog(@"The authenticity of host '%@' can't be established.", hostname); 149 | NSLog(@"See the UploadDelegate protocol for how to implement 'acceptUnknownHostFingerprint:forUpload:'"); 150 | } 151 | 152 | 153 | /* 154 | * Log warning for mismatched hostKey. 155 | */ 156 | - (void)showMismatchKeyWarningForHost:(NSString *)hostname 157 | { 158 | NSLog(@"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 159 | NSLog(@"@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); 160 | NSLog(@"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 161 | NSLog(@"Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); 162 | NSLog(@"It is also possible that the RSA host key for '%@' has just been changed.", hostname); 163 | NSLog(@"See the SSHDelegate protocol for how to implement 'acceptMismatchedHostFingerprint:forUpload:'"); 164 | } 165 | 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /objective-curl/src/CurlTransferStatus.h: -------------------------------------------------------------------------------- 1 | // 2 | // TransferStatus.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | typedef enum { 9 | CURL_TRANSFER_STATUS_QUEUED = 1, 10 | CURL_TRANSFER_STATUS_CONNECTING, 11 | CURL_TRANSFER_STATUS_CONNECTED, 12 | CURL_TRANSFER_STATUS_UPLOADING, 13 | CURL_TRANSFER_STATUS_COMPLETE, 14 | CURL_TRANSFER_STATUS_CANCELLED, 15 | CURL_TRANSFER_STATUS_LOGIN_DENIED, 16 | CURL_TRANSFER_STATUS_FAILED 17 | } CurlTransferStatus; 18 | -------------------------------------------------------------------------------- /objective-curl/src/CurlUpload.h: -------------------------------------------------------------------------------- 1 | // 2 | // Upload.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlRemoteObject.h" 10 | 11 | @class CurlFileTransfer; 12 | 13 | 14 | @interface CurlUpload : CurlRemoteObject 15 | { 16 | NSArray *localFiles; 17 | 18 | NSArray *transfers; 19 | 20 | CurlFileTransfer *currentTransfer; 21 | 22 | NSInteger progress; 23 | 24 | NSInteger totalFiles; 25 | 26 | NSInteger totalFilesUploaded; 27 | 28 | double totalBytes; 29 | 30 | double totalBytesUploaded; 31 | 32 | double lastBytesUploaded; 33 | 34 | double bytesPerSecond; 35 | 36 | double secondsRemaining; 37 | } 38 | 39 | 40 | @property(readwrite, retain) NSArray *localFiles; 41 | 42 | @property(readwrite, retain) NSArray *transfers; 43 | 44 | @property(readwrite, assign) CurlFileTransfer *currentTransfer; 45 | 46 | @property(readwrite, assign) NSInteger progress; 47 | 48 | @property(readwrite, assign) NSInteger totalFiles; 49 | 50 | @property(readwrite, assign) NSInteger totalFilesUploaded; 51 | 52 | @property(readwrite, assign) double totalBytes; 53 | 54 | @property(readwrite, assign) double totalBytesUploaded; 55 | 56 | @property(readwrite, assign) double lastBytesUploaded; 57 | 58 | @property(readwrite, assign) double bytesPerSecond; 59 | 60 | @property(readwrite, assign) double secondsRemaining; 61 | 62 | 63 | - (BOOL)isActive; 64 | 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /objective-curl/src/CurlUpload.m: -------------------------------------------------------------------------------- 1 | // 2 | // Upload.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "CurlUpload.h" 9 | #import "CurlTransferStatus.h" 10 | 11 | 12 | @implementation CurlUpload 13 | 14 | 15 | @synthesize localFiles; 16 | 17 | @synthesize transfers; 18 | 19 | @synthesize currentTransfer; 20 | 21 | @synthesize progress; 22 | 23 | @synthesize totalFiles; 24 | 25 | @synthesize totalFilesUploaded; 26 | 27 | @synthesize totalBytes; 28 | 29 | @synthesize totalBytesUploaded; 30 | 31 | @synthesize lastBytesUploaded; 32 | 33 | @synthesize bytesPerSecond; 34 | 35 | @synthesize secondsRemaining; 36 | 37 | 38 | - (id)init 39 | { 40 | if (self = [super init]) 41 | { 42 | [self setStatus:0]; 43 | [self setProgress:0]; 44 | [self setTotalFiles:0]; 45 | [self setTotalFilesUploaded:0]; 46 | [self setTotalBytes:0]; 47 | [self setTotalBytesUploaded:0]; 48 | [self setLastBytesUploaded:0]; 49 | } 50 | 51 | return self; 52 | } 53 | 54 | - (void)dealloc 55 | { 56 | [localFiles release]; 57 | [transfers release]; 58 | 59 | [super dealloc]; 60 | } 61 | 62 | - (BOOL)isActive 63 | { 64 | return (status == CURL_TRANSFER_STATUS_QUEUED || status == CURL_TRANSFER_STATUS_CONNECTING || status == CURL_TRANSFER_STATUS_UPLOADING); 65 | } 66 | 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /objective-curl/src/CurlUploadDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // UploadDelegate.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | 9 | @class CurlUpload; 10 | 11 | 12 | @protocol CurlUploadDelegate 13 | 14 | 15 | /* 16 | * Called when the upload has started. 17 | */ 18 | - (void)uploadDidBegin:(CurlUpload *)record; 19 | 20 | 21 | /* 22 | * Called when the upload has progressed, 1-100%. 23 | */ 24 | - (void)uploadDidProgress:(CurlUpload *)record toPercent:(NSNumber *)percent; 25 | 26 | 27 | /* 28 | * Called when the upload process has finished successfully. 29 | */ 30 | - (void)uploadDidFinish:(CurlUpload *)record; 31 | 32 | 33 | /* 34 | * Called if the upload was cancelled. 35 | */ 36 | - (void)uploadWasCancelled:(CurlUpload *)record; 37 | 38 | 39 | /* 40 | * Called when the upload has failed. The message will contain a useful description of what went wrong. 41 | */ 42 | - (void)uploadDidFail:(CurlUpload *)record message:(NSString *)message; 43 | 44 | 45 | /* 46 | * Implement this method to determine how a UNKNOWN host key fingerprint should be handled. 47 | * Return an integer indicating how to proceed. 48 | * 49 | * 0 = OK. Also add to known_hosts file 50 | * 1 = OK. 51 | * 2 = REJECT. 52 | * 3 = DEFER. Do not proceed, but leave the connection intact. This is the default if no delegate implementation exists. 53 | */ 54 | - (int)acceptUnknownHostFingerprint:(NSString *)fingerprint forUpload:(CurlUpload *)record; 55 | 56 | 57 | /* 58 | * Implement this method to determine how a MISMATCHED host key fingerprint should be handled. 59 | * See above for possible return values. 60 | */ 61 | - (int)acceptMismatchedHostFingerprint:(NSString *)fingerprint forUpload:(CurlUpload *)record; 62 | 63 | 64 | @end -------------------------------------------------------------------------------- /objective-curl/src/CurlUploadOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UploadOperation.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | #import "CurlOperation.h" 10 | #import "CurlClient.h" 11 | 12 | 13 | @class CurlUpload, CurlFileTransfer; 14 | 15 | 16 | @interface CurlUploadOperation : CurlOperation 17 | { 18 | CurlUpload *upload; 19 | } 20 | 21 | @property(readwrite, retain) CurlUpload *upload; 22 | 23 | static int handleUploadProgress(CurlUploadOperation *operation, int connected, double dltotal, double dlnow, double ultotal, double ulnow); 24 | 25 | -(BOOL)dependentOperationCancelled; 26 | 27 | - (void)calculateUploadProgress:(double)ulnow total:(double)ultotal; 28 | 29 | - (void)setProtocolSpecificOptions; 30 | 31 | - (void)setFileSpecificOptions:(CurlFileTransfer *)file; 32 | 33 | - (NSString *)urlForTransfer:(CurlFileTransfer *)file; 34 | 35 | - (NSArray *)enumerateFilesToUpload:(NSArray *)files prefix:(NSString *)prefix totalBytes:(double *)totalBytes; 36 | 37 | - (void)handleUploadResult:(CURLcode)result; 38 | 39 | - (void)handleUploadFailed:(CURLcode)result; 40 | 41 | - (void)notifyDelegateOfFailure; 42 | 43 | - (void)performDelegateSelector:(SEL)aSelector withArgument:(id)arg; 44 | 45 | - (NSString *)credentials; 46 | 47 | - (void)startByteTimer; 48 | 49 | - (void)enterByteTimerThread; 50 | 51 | - (void)calculateBytesPerSecond:(NSTimer *)timer; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /objective-curl/src/CurlUploadOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UploadOperation.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "NSObject+DDExtensions.h" 9 | #import "NSString+PathExtras.h" 10 | 11 | #import "CurlUploadOperation.h" 12 | #import "CurlFileTransfer.h" 13 | #import "CurlUpload.h" 14 | #import "CurlUploadDelegate.h" 15 | #import "CurlConnectionDelegate.h" 16 | #import "CurlTransferStatus.h" 17 | 18 | 19 | @implementation CurlUploadOperation 20 | 21 | 22 | @synthesize upload; 23 | 24 | 25 | /* 26 | * Thread entry point for recursive FTP uploads. 27 | */ 28 | - (void)main 29 | { 30 | if ([self isCancelled] || [self dependentOperationCancelled]) { 31 | 32 | [self notifyDelegateOfFailure]; 33 | 34 | return; 35 | } 36 | 37 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 38 | 39 | // Set options for uploading 40 | curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L); 41 | curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, self); 42 | curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, handleUploadProgress); 43 | 44 | // Set interface specific auth options 45 | [self setProtocolSpecificOptions]; 46 | 47 | double totalBytes = 0; 48 | 49 | // Enumurate files and directories to upload 50 | NSArray *filesToUpload = [[self enumerateFilesToUpload:[upload localFiles] 51 | prefix:[upload path] 52 | totalBytes:&totalBytes] retain]; 53 | 54 | [upload setTransfers:filesToUpload]; 55 | 56 | [upload setTotalFiles:[filesToUpload count]]; 57 | [upload setTotalFilesUploaded:0]; 58 | 59 | [upload setTotalBytes:totalBytes]; 60 | [upload setTotalBytesUploaded:0]; 61 | 62 | 63 | CURLcode result = -1; 64 | 65 | for (int i = 0; i < [filesToUpload count]; i++) 66 | { 67 | // Begin Uploading. 68 | CurlFileTransfer *file = [filesToUpload objectAtIndex:i]; 69 | 70 | [upload setCurrentTransfer:file]; 71 | 72 | if ([file fileNotFound]) 73 | { 74 | NSLog(@"Local file not found: %@", [file localPath]); 75 | continue; 76 | } 77 | 78 | [self setFileSpecificOptions:file]; 79 | 80 | FILE *fh = [file getHandle]; 81 | 82 | NSString *url = [self urlForTransfer:file]; 83 | 84 | curl_easy_setopt(handle, CURLOPT_READDATA, fh); 85 | curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)[file totalBytes]); 86 | curl_easy_setopt(handle, CURLOPT_URL, [url UTF8String]); 87 | 88 | // Perform 89 | result = curl_easy_perform(handle); 90 | 91 | // Cleanup any headers 92 | [file cleanupHeaders]; 93 | 94 | // Cleanup any quote commands 95 | [file cleanupPostQuotes]; 96 | 97 | // Close the file handle 98 | fclose(fh); 99 | 100 | // If this upload wasn't successful, bail out. 101 | if (result != CURLE_OK) 102 | break; 103 | 104 | // Increment total files uploaded 105 | [upload setTotalFilesUploaded:i + 1]; 106 | } 107 | 108 | // Cleanup Curl 109 | curl_easy_cleanup(handle); 110 | 111 | // Cleanup the files array. 112 | [filesToUpload release]; 113 | 114 | // Process the result of the upload. 115 | [self handleUploadResult:result]; 116 | 117 | // Done. 118 | [pool release]; 119 | } 120 | 121 | 122 | - (NSString *)urlForTransfer:(CurlFileTransfer *)file 123 | { 124 | NSString *filePath = [[file remotePath] stringByAddingTildePrefix]; 125 | 126 | NSString *path = [[NSString stringWithFormat:@"%@:%d", [upload hostname], [upload port]] 127 | stringByAppendingPathPreservingAbsolutePaths:filePath]; 128 | 129 | NSString *url = [NSString stringWithFormat:@"%@://%@", [upload protocolPrefix], path]; 130 | 131 | return url; 132 | } 133 | 134 | 135 | 136 | 137 | -(BOOL)dependentOperationCancelled 138 | { 139 | BOOL answer = NO; 140 | 141 | for (int i = 0; i < [[self dependencies] count]; i++) { 142 | NSOperation *dependency = [[self dependencies] objectAtIndex:i]; 143 | 144 | if ([dependency isCancelled]) { 145 | answer = YES; 146 | break; 147 | } 148 | } 149 | 150 | return answer; 151 | } 152 | 153 | 154 | - (void)setProtocolSpecificOptions 155 | { 156 | curl_easy_setopt(handle, CURLOPT_USERPWD, [[self credentials] UTF8String]); 157 | curl_easy_setopt(handle, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L); 158 | } 159 | 160 | 161 | - (void)setFileSpecificOptions:(CurlFileTransfer *)file 162 | { 163 | if ([file isEmptyDirectory]) 164 | { 165 | const char *removeTempFile = [[NSString stringWithFormat:@"DELE %@", [CurlFileTransfer emptyFilename]] UTF8String]; 166 | 167 | [file appendPostQuote:removeTempFile]; 168 | } 169 | 170 | curl_easy_setopt(handle, CURLOPT_POSTQUOTE, [file postQuote]); 171 | } 172 | 173 | 174 | 175 | /* 176 | * Used to handle upload progress if the showProgress flag is set. Invoked by libcurl on progress updates to calculates the 177 | * new upload progress and sets it on the upload. 178 | * 179 | * See http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTPROGRESSFUNCTION 180 | */ 181 | static int handleUploadProgress(CurlUploadOperation *operation, int connected, double dltotal, double dlnow, double ultotal, double ulnow) 182 | { 183 | CurlUpload *upload = [operation upload]; 184 | 185 | if ([upload connected] && !connected) return 0; // Reconnecting... 186 | 187 | if (!connected) 188 | { 189 | if ([upload status] != CURL_TRANSFER_STATUS_CONNECTING) 190 | { 191 | // Connecting ... 192 | [upload setConnected:NO]; 193 | [upload setStatus:CURL_TRANSFER_STATUS_CONNECTING]; 194 | 195 | // Notify the delegate 196 | [operation performDelegateSelector:@selector(curlIsConnecting:) withArgument:nil]; 197 | } 198 | 199 | } 200 | else 201 | { 202 | if (![upload connected]) 203 | { 204 | // We have a connection. 205 | [upload setConnected:YES]; 206 | [upload setStatus:CURL_TRANSFER_STATUS_CONNECTED]; 207 | 208 | // Notify the delegate 209 | [operation performDelegateSelector:@selector(curlDidConnect:) withArgument:nil]; 210 | } 211 | 212 | if ([upload connected] && [upload status] != CURL_TRANSFER_STATUS_UPLOADING && ulnow > 0) 213 | { 214 | [upload setStatus:CURL_TRANSFER_STATUS_UPLOADING]; 215 | 216 | // Notify the delegate 217 | [operation performDelegateSelector:@selector(uploadDidBegin:) withArgument:nil]; 218 | 219 | // Start the BPS timer 220 | [operation startByteTimer]; 221 | } 222 | 223 | if (ulnow > ultotal) return 0; // This happens occasionally, not sure why... 224 | 225 | [operation calculateUploadProgress:ulnow total:ultotal]; 226 | } 227 | 228 | return ([upload cancelled] || [upload status] == CURL_TRANSFER_STATUS_FAILED); 229 | } 230 | 231 | 232 | 233 | 234 | - (void)calculateUploadProgress:(double)ulnow total:(double)ultotal 235 | { 236 | // Compute the current files bytes uploaded 237 | double currentBytesUploaded = [[upload currentTransfer] isEmptyDirectory] ? [[upload currentTransfer] totalBytes] : ulnow; 238 | 239 | // Compute the total bytes uploaded 240 | double totalBytesUploaded = [upload totalBytesUploaded] + (currentBytesUploaded - [[upload currentTransfer] totalBytesUploaded]); 241 | 242 | // Compute current files percentage complete 243 | double percentComplete = [[upload currentTransfer] isEmptyDirectory] ? 100 : (ulnow * 100 / ultotal); 244 | 245 | [[upload currentTransfer] setTotalBytesUploaded:currentBytesUploaded]; 246 | [[upload currentTransfer] setPercentComplete:percentComplete]; 247 | 248 | [upload setTotalBytesUploaded:totalBytesUploaded]; 249 | 250 | // Compute the total percent complete of the entire transfer 251 | int progressNow = ([upload totalBytesUploaded] * 100 / [upload totalBytes]); 252 | 253 | if (progressNow >= [upload progress]) 254 | { 255 | // Set the current progress 256 | [upload setProgress:progressNow]; 257 | 258 | // Notify the delegate 259 | [self performDelegateSelector:@selector(uploadDidProgress:toPercent:) 260 | withArgument:[NSNumber numberWithInt:progressNow]]; 261 | } 262 | } 263 | 264 | 265 | 266 | 267 | /* 268 | * Called when the upload loop execution has finished. Updates the state of the upload and notifies delegates. 269 | * 270 | */ 271 | - (void)handleUploadResult:(CURLcode)result 272 | { 273 | if (result == CURLE_OK && [upload totalFiles] == [upload totalFilesUploaded]) 274 | { 275 | // Success! 276 | [upload setStatus:CURL_TRANSFER_STATUS_COMPLETE]; 277 | 278 | // Notify Delegates 279 | [self performDelegateSelector:@selector(uploadDidFinish:) 280 | withArgument:nil]; 281 | } 282 | else if ([upload cancelled]) 283 | { 284 | // Cancelled! 285 | [upload setStatus:CURL_TRANSFER_STATUS_CANCELLED]; 286 | 287 | // Notify Delegate 288 | [self performDelegateSelector:@selector(uploadWasCancelled:) 289 | withArgument:nil]; 290 | } 291 | else 292 | { 293 | // Handle Failure 294 | [self handleUploadFailed:result]; 295 | } 296 | } 297 | 298 | 299 | 300 | /* 301 | * Handles a failed upload. Figures out what went wrong and notifies the delegate. 302 | * 303 | */ 304 | - (void)handleUploadFailed:(CURLcode)result 305 | { 306 | // The upload operation failed. 307 | int status; 308 | switch (result) 309 | { 310 | // Auth Failure 311 | case CURLE_LOGIN_DENIED: 312 | status = CURL_TRANSFER_STATUS_LOGIN_DENIED; 313 | break; 314 | 315 | // General Failure 316 | default: 317 | status = CURL_TRANSFER_STATUS_FAILED; 318 | break; 319 | } 320 | 321 | [upload setStatus:status]; 322 | [upload setStatusMessage:[self getFailureDetailsForStatus:result withObject:upload]]; 323 | 324 | [self notifyDelegateOfFailure]; 325 | } 326 | 327 | 328 | 329 | - (void)notifyDelegateOfFailure 330 | { 331 | if (delegate && [delegate respondsToSelector:@selector(uploadDidFail:message:)]) 332 | { 333 | [[delegate invokeOnMainThread] uploadDidFail:upload message:[upload statusMessage]]; 334 | } 335 | } 336 | 337 | 338 | 339 | /* 340 | * Takes in a list of files and directories to be uploaded, and returns an array of FileTransfers. 341 | * Gets the job done, but the code is a mess and I'm pretty sure it's leaking. 342 | * 343 | */ 344 | - (NSArray *)enumerateFilesToUpload:(NSArray *)files prefix:(NSString *)prefix totalBytes:(double *)totalBytes 345 | { 346 | NSMutableArray *filesToUpload = [[NSMutableArray alloc] init]; 347 | NSFileManager *mgr = [NSFileManager defaultManager]; 348 | 349 | BOOL isDir; 350 | for (int i = 0; i < [files count]; i++) 351 | { 352 | NSString *pathToFile = [files objectAtIndex:i]; 353 | 354 | CurlFileTransfer *pendingTransfer = nil; 355 | 356 | if ([mgr fileExistsAtPath:pathToFile isDirectory:&isDir] && !isDir) 357 | { 358 | // Regular File 359 | 360 | pendingTransfer = [[CurlFileTransfer alloc] initWithLocalPath:pathToFile 361 | remotePath:[prefix stringByAppendingPathComponent:[pathToFile lastPathComponent]]]; 362 | } 363 | else if ([[mgr contentsOfDirectoryAtPath:pathToFile error:nil] count] > 0) 364 | { 365 | // Non-Empty Directory 366 | 367 | NSDirectoryEnumerator *dir = [mgr enumeratorAtPath:pathToFile]; 368 | NSString *basePath = [pathToFile lastPathComponent]; 369 | NSString *filename = NULL; 370 | 371 | while (filename = [dir nextObject]) 372 | { 373 | NSString *nextPath = [pathToFile stringByAppendingPathComponent:filename]; 374 | 375 | if ([mgr fileExistsAtPath:nextPath isDirectory:&isDir] && !isDir) 376 | { 377 | pendingTransfer = [[CurlFileTransfer alloc] initWithLocalPath:nextPath 378 | remotePath:[prefix stringByAppendingPathComponent:[basePath stringByAppendingPathComponent:filename]]]; 379 | 380 | } 381 | else if ([[mgr contentsOfDirectoryAtPath:nextPath error:nil] count] == 0) 382 | { 383 | pendingTransfer = [[CurlFileTransfer alloc] initWithLocalPath:nextPath 384 | remotePath:[prefix stringByAppendingPathComponent:[basePath stringByAppendingPathComponent:filename]]]; 385 | 386 | [pendingTransfer setIsEmptyDirectory:YES]; 387 | [pendingTransfer setRemotePath:[[pendingTransfer remotePath] 388 | stringByAppendingPathComponent:[CurlFileTransfer emptyFilename]]]; 389 | } 390 | else 391 | { 392 | continue; 393 | } 394 | 395 | if ([pendingTransfer isEmptyDirectory] || [pendingTransfer fileNotFound]) { 396 | 397 | [pendingTransfer setTotalBytes:0]; 398 | } 399 | else { 400 | 401 | NSError *err = nil; 402 | NSString *filePath = [[pendingTransfer localPath] stringByResolvingSymlinksInPath]; 403 | NSDictionary *fileAttrs = [mgr attributesOfItemAtPath:filePath error:&err]; 404 | double fileSize = 0; 405 | if (!err) { 406 | 407 | fileSize = [[fileAttrs objectForKey:NSFileSize] doubleValue]; 408 | } 409 | 410 | [pendingTransfer setTotalBytes:fileSize]; 411 | } 412 | // Add to totalBytes 413 | *totalBytes += [pendingTransfer totalBytes]; 414 | 415 | [filesToUpload addObject:pendingTransfer]; 416 | } 417 | 418 | continue; 419 | } 420 | else 421 | { 422 | pendingTransfer = [[CurlFileTransfer alloc] initWithLocalPath:pathToFile 423 | remotePath:[prefix stringByAppendingPathComponent:[pathToFile lastPathComponent]]]; 424 | 425 | if ([mgr fileExistsAtPath:pathToFile]) 426 | { 427 | // Empty Directory 428 | [pendingTransfer setIsEmptyDirectory:YES]; 429 | [pendingTransfer setRemotePath:[[pendingTransfer remotePath] 430 | stringByAppendingPathComponent:[CurlFileTransfer emptyFilename]]]; 431 | 432 | } 433 | else 434 | { 435 | // Not Found 436 | [pendingTransfer setFileNotFound:YES]; 437 | } 438 | } 439 | 440 | if ([pendingTransfer isEmptyDirectory] || [pendingTransfer fileNotFound]) { 441 | 442 | [pendingTransfer setTotalBytes:0]; 443 | } 444 | else { 445 | 446 | NSError *err = nil; 447 | NSString *filePath = [[pendingTransfer localPath] stringByResolvingSymlinksInPath]; 448 | NSDictionary *fileAttrs = [mgr attributesOfItemAtPath:filePath error:&err]; 449 | double fileSize = 0; 450 | 451 | if (!err) { 452 | 453 | fileSize = [[fileAttrs objectForKey:NSFileSize] doubleValue]; 454 | } 455 | 456 | [pendingTransfer setTotalBytes:fileSize]; 457 | } 458 | 459 | // Add to totalBytes 460 | *totalBytes += [pendingTransfer totalBytes]; 461 | 462 | 463 | [filesToUpload addObject:pendingTransfer]; 464 | 465 | } 466 | 467 | return [filesToUpload autorelease]; 468 | } 469 | 470 | 471 | /* 472 | * Calls an UploadDelegate method on the main thread. 473 | * 474 | */ 475 | - (void)performDelegateSelector:(SEL)aSelector withArgument:(id)arg 476 | { 477 | if (delegate && [delegate respondsToSelector:aSelector]) 478 | { 479 | if (arg) 480 | { 481 | [[delegate invokeOnMainThread] performSelector:aSelector withObject:upload withObject:arg]; 482 | } 483 | else 484 | { 485 | [[delegate invokeOnMainThread] performSelector:aSelector withObject:upload]; 486 | } 487 | } 488 | } 489 | 490 | 491 | 492 | /* 493 | * Returns a string that can be used for FTP authentication, "username:password", if no username is specified then "anonymous" will 494 | * be used. If a username is present but no password is set, then the users keychain is checked. 495 | * 496 | */ 497 | - (NSString *)credentials 498 | { 499 | NSString *creds; 500 | if ([upload hasAuthUsername]) 501 | { 502 | creds = [NSString stringWithFormat:@"%@:%@", [upload username], [upload password]]; 503 | } 504 | else 505 | { 506 | // Try anonymous login 507 | creds = [NSString stringWithFormat:@"anonymous:"]; 508 | } 509 | 510 | return creds; 511 | } 512 | 513 | 514 | /* 515 | * Cleanup. Release the upload. 516 | * 517 | */ 518 | - (void)dealloc 519 | { 520 | [upload release]; 521 | 522 | [super dealloc]; 523 | } 524 | 525 | 526 | - (void)startByteTimer 527 | { 528 | NSThread* timerThread = [[NSThread alloc] initWithTarget:self 529 | selector:@selector(enterByteTimerThread) 530 | object:nil]; 531 | [timerThread start]; 532 | } 533 | 534 | 535 | - (void)enterByteTimerThread 536 | { 537 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 538 | NSRunLoop* runLoop = [NSRunLoop currentRunLoop]; 539 | 540 | [[NSTimer scheduledTimerWithTimeInterval:2.0 541 | target:self 542 | selector:@selector(calculateBytesPerSecond:) 543 | userInfo:nil 544 | repeats:YES] retain]; 545 | 546 | [runLoop run]; 547 | [pool release]; 548 | } 549 | 550 | 551 | - (void)calculateBytesPerSecond:(NSTimer *)timer 552 | { 553 | if ([upload isActive]) 554 | { 555 | double bps = [upload totalBytesUploaded] - [upload lastBytesUploaded]; 556 | double sr = ([upload totalBytes] - [upload totalBytesUploaded]) / bps; 557 | 558 | [upload setBytesPerSecond:bps]; 559 | [upload setSecondsRemaining:sr]; 560 | [upload setLastBytesUploaded:[upload totalBytesUploaded]]; 561 | } 562 | else 563 | { 564 | [timer invalidate]; 565 | [timer release]; 566 | } 567 | } 568 | 569 | 570 | @end 571 | -------------------------------------------------------------------------------- /objective-curl/src/DDInvocationGrabber.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2008 Dave Dribin 3 | * 4 | * Permission is hereby granted, free of charge, to any person 5 | * obtaining a copy of this software and associated documentation 6 | * files (the "Software"), to deal in the Software without 7 | * restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies 9 | * of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 26 | /* 27 | * This class is based on CInvocationGrabber: 28 | * 29 | * Copyright (c) 2007, Toxic Software 30 | * All rights reserved. 31 | * Redistribution and use in source and binary forms, with or without 32 | * modification, are permitted provided that the following conditions are 33 | * met: 34 | * 35 | * * Redistributions of source code must retain the above copyright notice, 36 | * this list of conditions and the following disclaimer. 37 | * 38 | * * Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 42 | * * Neither the name of the Toxic Software nor the names of its 43 | * contributors may be used to endorse or promote products derived from 44 | * this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 49 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 50 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 56 | * THE POSSIBILITY OF SUCH DAMAGE. 57 | * 58 | */ 59 | 60 | #import 61 | 62 | /** 63 | * @class DDInvocationGrabber 64 | * @discussion DDInvocationGrabber is a helper object that makes it very easy to construct instances of NSInvocation for later use. The object is inspired by NSUndoManager's prepareWithInvocationTarget method. To use a DDInvocationGrabber object, you set its target to some object, then send it a message as if it were the target object (the DDInvocationGrabber object acts as a proxy), if the target message understands the message the DDInvocationGrabber object stores the message invocation. 65 | 66 | DDInvocationGrabber *theGrabber = [DDInvocationGrabber invocationGrabber]; 67 | [theGrabber setTarget:someObject] 68 | [theGrabber doSomethingWithParameter:someParameter]; // Send messages to 'theGrabber' as if it were 'someObject' 69 | NSInvocation *theInvocation = [theGrabber invocation]; 70 | 71 | A slightly more concise version (using the covenience category) follows: 72 | 73 | DDInvocationGrabber *theGrabber = [DDInvocationGrabber invocationGrabber]; 74 | [[theGrabber prepareWithInvocationTarget:someObject] doSomethingWithParameter:someParameter]; 75 | NSInvocation *theInvocation = [theGrabber invocation]; 76 | 77 | */ 78 | @interface InvocationGrabber : NSProxy 79 | { 80 | id _target; 81 | NSInvocation * _invocation; 82 | BOOL _forwardInvokesOnMainThread; 83 | BOOL _waitUntilDone; 84 | } 85 | 86 | /** 87 | * @method invocationGrabber 88 | * @abstract Returns a newly allocated, inited, autoreleased DDInvocationGrabber object. 89 | */ 90 | + (id)invocationGrabber; 91 | 92 | - (id)target; 93 | - (void)setTarget:(id)inTarget; 94 | 95 | - (NSInvocation *)invocation; 96 | - (void)setInvocation:(NSInvocation *)inInvocation; 97 | 98 | - (BOOL)forwardInvokesOnMainThread; 99 | - (void)setForwardInvokesOnMainThread:(BOOL)forwardInvokesOnMainThread; 100 | 101 | - (BOOL)waitUntilDone; 102 | - (void)setWaitUntilDone:(BOOL)waitUntilDone; 103 | 104 | @end 105 | 106 | @interface InvocationGrabber (DDInvocationGrabber_Conveniences) 107 | 108 | /** 109 | * @method prepareWithInvocationTarget: 110 | * @abstract Sets the target object of the receiver and returns itself. The sender can then send a message to the 111 | */ 112 | - (id)prepareWithInvocationTarget:(id)inTarget; 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /objective-curl/src/DDInvocationGrabber.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2008 Dave Dribin 3 | * 4 | * Permission is hereby granted, free of charge, to any person 5 | * obtaining a copy of this software and associated documentation 6 | * files (the "Software"), to deal in the Software without 7 | * restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies 9 | * of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | 26 | /* 27 | * This class is based on CInvocationGrabber: 28 | * 29 | * Copyright (c) 2007, Toxic Software 30 | * All rights reserved. 31 | * Redistribution and use in source and binary forms, with or without 32 | * modification, are permitted provided that the following conditions are 33 | * met: 34 | * 35 | * * Redistributions of source code must retain the above copyright notice, 36 | * this list of conditions and the following disclaimer. 37 | * 38 | * * Redistributions in binary form must reproduce the above copyright 39 | * notice, this list of conditions and the following disclaimer in the 40 | * documentation and/or other materials provided with the distribution. 41 | * 42 | * * Neither the name of the Toxic Software nor the names of its 43 | * contributors may be used to endorse or promote products derived from 44 | * this software without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 49 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 50 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 56 | * THE POSSIBILITY OF SUCH DAMAGE. 57 | * 58 | */ 59 | 60 | #import "DDInvocationGrabber.h" 61 | 62 | 63 | @implementation InvocationGrabber 64 | 65 | + (id)invocationGrabber 66 | { 67 | return([[[self alloc] init] autorelease]); 68 | } 69 | 70 | - (id)init 71 | { 72 | _target = nil; 73 | _invocation = nil; 74 | _forwardInvokesOnMainThread = NO; 75 | _waitUntilDone = NO; 76 | 77 | return self; 78 | } 79 | 80 | - (void)dealloc 81 | { 82 | [self setTarget:NULL]; 83 | [self setInvocation:NULL]; 84 | // 85 | [super dealloc]; 86 | } 87 | 88 | #pragma mark - 89 | 90 | - (id)target 91 | { 92 | return _target; 93 | } 94 | 95 | - (void)setTarget:(id)inTarget 96 | { 97 | if (_target != inTarget) 98 | { 99 | [_target autorelease]; 100 | _target = [inTarget retain]; 101 | } 102 | } 103 | 104 | - (NSInvocation *)invocation 105 | { 106 | return _invocation; 107 | } 108 | 109 | - (void)setInvocation:(NSInvocation *)inInvocation 110 | { 111 | if (_invocation != inInvocation) 112 | { 113 | [_invocation autorelease]; 114 | _invocation = [inInvocation retain]; 115 | } 116 | } 117 | 118 | - (BOOL)forwardInvokesOnMainThread; 119 | { 120 | return _forwardInvokesOnMainThread; 121 | } 122 | 123 | - (void)setForwardInvokesOnMainThread:(BOOL)forwardInvokesOnMainThread; 124 | { 125 | _forwardInvokesOnMainThread = forwardInvokesOnMainThread; 126 | } 127 | 128 | - (BOOL)waitUntilDone; 129 | { 130 | return _waitUntilDone; 131 | } 132 | 133 | - (void)setWaitUntilDone:(BOOL)waitUntilDone; 134 | { 135 | _waitUntilDone = waitUntilDone; 136 | } 137 | 138 | #pragma mark - 139 | 140 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector 141 | { 142 | return [[self target] methodSignatureForSelector:selector]; 143 | } 144 | 145 | - (void)forwardInvocation:(NSInvocation *)ioInvocation 146 | { 147 | [ioInvocation setTarget:[self target]]; 148 | [self setInvocation:ioInvocation]; 149 | if (_forwardInvokesOnMainThread) 150 | { 151 | if (!_waitUntilDone) 152 | [_invocation retainArguments]; 153 | [_invocation performSelectorOnMainThread:@selector(invoke) 154 | withObject:nil 155 | waitUntilDone:_waitUntilDone]; 156 | } 157 | } 158 | 159 | @end 160 | 161 | #pragma mark - 162 | 163 | @implementation InvocationGrabber (DDnvocationGrabber_Conveniences) 164 | 165 | - (id)prepareWithInvocationTarget:(id)inTarget 166 | { 167 | [self setTarget:inTarget]; 168 | return(self); 169 | } 170 | 171 | @end 172 | -------------------------------------------------------------------------------- /objective-curl/src/NSFileManager+MimeType.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+MimeType.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | 10 | 11 | @interface NSFileManager (MimeType) 12 | 13 | 14 | + (NSString *)mimeTypeForFileAtPath:(NSString *)path; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /objective-curl/src/NSFileManager+MimeType.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSFileManager+MimeType.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "NSFileManager+MimeType.h" 9 | 10 | 11 | @implementation NSFileManager (MimeType) 12 | 13 | + (NSString *)mimeTypeForFileAtPath:(NSString *)path 14 | { 15 | BOOL isDir = NO; 16 | NSFileManager *mgr = [[NSFileManager alloc] init]; 17 | NSString *mimeType = @""; 18 | 19 | if ([mgr fileExistsAtPath:path isDirectory:&isDir] && isDir) 20 | { 21 | mimeType = @"application/x-directory"; 22 | } 23 | else 24 | { 25 | NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]; 26 | NSURLResponse *resp = nil; 27 | NSError *err = nil; 28 | 29 | [NSURLConnection sendSynchronousRequest:req 30 | returningResponse:&resp 31 | error:&err]; 32 | if (!err) 33 | { 34 | mimeType = [resp MIMEType]; 35 | } 36 | else 37 | { 38 | NSLog(@"Error trying to get MimeType of file: %@ - %@", path, [err description]); 39 | } 40 | } 41 | 42 | [mgr release]; 43 | 44 | return mimeType; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /objective-curl/src/NSObject+DDExtensions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2008 Dave Dribin 3 | * 4 | * Permission is hereby granted, free of charge, to any person 5 | * obtaining a copy of this software and associated documentation 6 | * files (the "Software"), to deal in the Software without 7 | * restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies 9 | * of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #import 26 | 27 | 28 | @interface NSObject (DDExtensions) 29 | 30 | - (id)invokeOnMainThread; 31 | - (id)invokeOnMainThreadAndWaitUntilDone:(BOOL)waitUntilDone; 32 | 33 | @end 34 | 35 | #define ddsynthesize(_X_) @synthesize _X_ = _##_X_ 36 | -------------------------------------------------------------------------------- /objective-curl/src/NSObject+DDExtensions.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007-2008 Dave Dribin 3 | * 4 | * Permission is hereby granted, free of charge, to any person 5 | * obtaining a copy of this software and associated documentation 6 | * files (the "Software"), to deal in the Software without 7 | * restriction, including without limitation the rights to use, copy, 8 | * modify, merge, publish, distribute, sublicense, and/or sell copies 9 | * of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #import "NSObject+DDExtensions.h" 26 | #import "DDInvocationGrabber.h" 27 | 28 | @implementation NSObject (DDExtensions) 29 | 30 | - (id)invokeOnMainThread; 31 | { 32 | return [self invokeOnMainThreadAndWaitUntilDone:NO]; 33 | } 34 | 35 | - (id)invokeOnMainThreadAndWaitUntilDone:(BOOL)waitUntilDone; 36 | { 37 | InvocationGrabber * grabber = [InvocationGrabber invocationGrabber]; 38 | [grabber setForwardInvokesOnMainThread:YES]; 39 | [grabber setWaitUntilDone:waitUntilDone]; 40 | return [grabber prepareWithInvocationTarget:self]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /objective-curl/src/NSString+MD5.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @header NSString+MD5.h 3 | @abstract Category methods for creating MD5 hashes as strings. 4 | @discussion Category methods for creating MD5 hashes as strings. 5 | */ 6 | 7 | 8 | #import 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | @interface NSString (MD5) 15 | 16 | /* 17 | * Create an MD5 hash in the format of XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX 18 | */ 19 | + (NSString *)formattedMD5:(const char *)data length:(unsigned long)len; 20 | 21 | /* 22 | * Same as above, but takes in the Base64 encoded data found in the ~/.ssh/known_hosts file. 23 | */ 24 | + (NSString *)formattedMD5FromBase64:(const char *)data length:(unsigned long)len; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /objective-curl/src/NSString+MD5.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+MD5.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "NSString+MD5.h" 9 | 10 | 11 | @implementation NSString (MD5) 12 | 13 | + (NSString *)formattedMD5:(const char *)data length:(unsigned long)len 14 | { 15 | unsigned char *digest = MD5((unsigned const char *)data, len, NULL); 16 | NSMutableArray *values = [[NSMutableArray alloc] init]; 17 | 18 | for (int i = 0; i < strlen((char *)digest); i++) 19 | { 20 | char hexValue[4]; 21 | sprintf(hexValue, "%02X", digest[i]); 22 | [values addObject:[NSString stringWithUTF8String:hexValue]]; 23 | } 24 | 25 | return [values componentsJoinedByString:@":"]; 26 | } 27 | 28 | + (NSString *)formattedMD5FromBase64:(const char *)data length:(unsigned long)len 29 | { 30 | BIO *b64, *bmem; 31 | 32 | char *buffer = (char *)malloc(len); 33 | memset(buffer, 0, len); 34 | 35 | b64 = BIO_new(BIO_f_base64()); 36 | 37 | BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); 38 | 39 | bmem = BIO_new_mem_buf((char *)data, (int)len); 40 | bmem = BIO_push(b64, bmem); 41 | 42 | BIO_read(bmem, buffer, (int)len); 43 | 44 | BIO_free_all(bmem); 45 | 46 | NSString *result = [NSString formattedMD5:buffer length:len]; 47 | 48 | free(buffer); 49 | 50 | return result; 51 | } 52 | 53 | 54 | 55 | @end -------------------------------------------------------------------------------- /objective-curl/src/NSString+PathExtras.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @header NSString+PathExtras 3 | @abstract Category methods for creating FTP-safe paths. 4 | @discussion Category methods for creating FTP-safe paths. 5 | */ 6 | 7 | 8 | #import 9 | 10 | 11 | @interface NSString (PathExtras) 12 | 13 | - (NSString *)stringByAppendingPathPreservingAbsolutePaths:(NSString *)str; 14 | - (NSString *)stringByAddingTildePrefix; 15 | - (NSString *)stringByRemovingTildePrefix; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /objective-curl/src/NSString+PathExtras.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+PathExtras.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "NSString+PathExtras.h" 9 | 10 | 11 | @implementation NSString (PathExtras) 12 | 13 | 14 | - (NSString *)stringByAppendingPathPreservingAbsolutePaths:(NSString *)str 15 | { 16 | NSMutableString *res = [[self stringByAppendingPathComponent:str] mutableCopy]; 17 | 18 | if ([[str substringToIndex:1] isEqualToString:@"/"]) 19 | { 20 | [res replaceCharactersInRange:[res rangeOfString:@"/"] withString:@"//"]; 21 | } 22 | 23 | return (NSString *)res; 24 | } 25 | 26 | - (NSString *)stringByAddingTildePrefix 27 | { 28 | if ([self isEqualToString:@""]) 29 | return @"~/"; 30 | 31 | NSMutableString *path; 32 | 33 | // Not an absolute path, add a tilde prefix. 34 | if(![[self substringToIndex:1] isEqualToString:@"~"] && ![[self substringToIndex:1] isEqualToString:@"/"]) 35 | path = [NSMutableString stringWithString:[@"~/" stringByAppendingPathComponent:self]]; 36 | else 37 | path = [NSMutableString stringWithString:self]; 38 | 39 | return path; 40 | } 41 | 42 | 43 | - (NSString *)stringByRemovingTildePrefix 44 | { 45 | if ([[self substringToIndex:2] isEqualToString:@"~/"]) 46 | { 47 | return [self substringFromIndex:2]; 48 | } 49 | 50 | return self; 51 | } 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /objective-curl/src/NSString+S3.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+S3.h 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import 9 | 10 | 11 | @interface NSString (S3) 12 | 13 | - (NSString *)signS3PutRequestWithKey:(NSString *)key; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /objective-curl/src/NSString+S3.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+S3.m 3 | // objective-curl 4 | // 5 | // Copyright 2010 Nick Jensen 6 | // 7 | 8 | #import "NSString+S3.h" 9 | #import 10 | 11 | @implementation NSString (S3) 12 | 13 | 14 | - (NSString *)signS3PutRequestWithKey:(NSString *)key 15 | { 16 | NSData *clearTextData = [self dataUsingEncoding:NSUTF8StringEncoding]; 17 | NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding]; 18 | 19 | uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0}; 20 | 21 | CCHmacContext hmacContext; 22 | CCHmacInit(&hmacContext, kCCHmacAlgSHA1, keyData.bytes, keyData.length); 23 | CCHmacUpdate(&hmacContext, clearTextData.bytes, clearTextData.length); 24 | CCHmacFinal(&hmacContext, digest); 25 | 26 | NSData *data = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; 27 | 28 | static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 29 | 30 | if ([data length] == 0) 31 | return @""; 32 | 33 | char *characters = malloc((([data length] + 2) / 3) * 4); 34 | if (characters == NULL) 35 | return nil; 36 | NSUInteger length = 0; 37 | 38 | NSUInteger i = 0; 39 | while (i < [data length]) 40 | { 41 | char buffer[3] = {0,0,0}; 42 | short bufferLength = 0; 43 | while (bufferLength < 3 && i < [data length]) 44 | buffer[bufferLength++] = ((char *)[data bytes])[i++]; 45 | 46 | // Encode the bytes in the buffer to four characters, including padding "=" characters if necessary. 47 | characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2]; 48 | characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)]; 49 | 50 | if (bufferLength > 1) 51 | characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)]; 52 | else characters[length++] = '='; 53 | 54 | if (bufferLength > 2) 55 | characters[length++] = encodingTable[buffer[2] & 0x3F]; 56 | else characters[length++] = '='; 57 | } 58 | 59 | return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease]; 60 | } 61 | 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /objective-curl/src/NSString+URLEncoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+URLEncoding.h 3 | // 4 | // Created by Jon Crosby on 10/19/07. 5 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import 27 | 28 | 29 | @interface NSString (OAURLEncodingAdditions) 30 | 31 | - (NSString *)encodedURLString; 32 | - (NSString *)encodedURLParameterString; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /objective-curl/src/NSString+URLEncoding.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+URLEncoding.m 3 | // 4 | // Created by Jon Crosby on 10/19/07. 5 | // Copyright 2007 Kaboomerang LLC. All rights reserved. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | 26 | #import "NSString+URLEncoding.h" 27 | 28 | 29 | @implementation NSString (OAURLEncodingAdditions) 30 | 31 | - (NSString *)encodedURLString { 32 | NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 33 | (CFStringRef)self, 34 | NULL, // characters to leave unescaped (NULL = all escaped sequences are replaced) 35 | CFSTR("?=&+"), // legal URL characters to be escaped (NULL = all legal characters are replaced) 36 | kCFStringEncodingUTF8); // encoding 37 | return result; 38 | } 39 | 40 | - (NSString *)encodedURLParameterString { 41 | NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, 42 | (CFStringRef)self, 43 | NULL, 44 | CFSTR(":/=,!$&'()*+;[]@#?"), 45 | kCFStringEncodingUTF8); 46 | return result; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /objective-curl/src/ftpparse.c: -------------------------------------------------------------------------------- 1 | /* ftpparse.c, ftpparse.h: library for parsing FTP LIST responses 2 | 20001223 3 | D. J. Bernstein, djb@cr.yp.to 4 | http://cr.yp.to/ftpparse.html 5 | 6 | Commercial use is fine, if you let me know what programs you're using this in. 7 | 8 | Currently covered formats: 9 | EPLF. 10 | UNIX ls, with or without gid. 11 | Microsoft FTP Service. 12 | Windows NT FTP Server. 13 | VMS. 14 | WFTPD. 15 | NetPresenz (Mac). 16 | NetWare. 17 | MSDOS. 18 | 19 | Definitely not covered: 20 | Long VMS filenames, with information split across two lines. 21 | NCSA Telnet FTP server. Has LIST = NLST (and bad NLST for directories). 22 | */ 23 | 24 | #include 25 | #include "ftpparse.h" 26 | 27 | static long totai(long year,long month,long mday) 28 | { 29 | long result; 30 | if (month >= 2) month -= 2; 31 | else { month += 10; --year; } 32 | result = (mday - 1) * 10 + 5 + 306 * month; 33 | result /= 10; 34 | if (result == 365) { year -= 3; result = 1460; } 35 | else result += 365 * (year % 4); 36 | year /= 4; 37 | result += 1461 * (year % 25); 38 | year /= 25; 39 | if (result == 36524) { year -= 3; result = 146096; } 40 | else { result += 36524 * (year % 4); } 41 | year /= 4; 42 | result += 146097 * (year - 5); 43 | result += 11017; 44 | return result * 86400; 45 | } 46 | 47 | static int flagneedbase = 1; 48 | static time_t base; /* time() value on this OS at the beginning of 1970 TAI */ 49 | static long now; /* current time */ 50 | static int flagneedcurrentyear = 1; 51 | static long currentyear; /* approximation to current year */ 52 | 53 | static void initbase(void) 54 | { 55 | struct tm *t; 56 | if (!flagneedbase) return; 57 | 58 | base = 0; 59 | t = gmtime(&base); 60 | base = -(totai(t->tm_year + 1900,t->tm_mon,t->tm_mday) + t->tm_hour * 3600 + t->tm_min * 60 + t->tm_sec); 61 | /* assumes the right time_t, counting seconds. */ 62 | /* base may be slightly off if time_t counts non-leap seconds. */ 63 | flagneedbase = 0; 64 | } 65 | 66 | static void initnow(void) 67 | { 68 | long day; 69 | long year; 70 | 71 | initbase(); 72 | now = time((time_t *) 0) - base; 73 | 74 | if (flagneedcurrentyear) { 75 | day = now / 86400; 76 | if ((now % 86400) < 0) --day; 77 | day -= 11017; 78 | year = 5 + day / 146097; 79 | day = day % 146097; 80 | if (day < 0) { day += 146097; --year; } 81 | year *= 4; 82 | if (day == 146096) { year += 3; day = 36524; } 83 | else { year += day / 36524; day %= 36524; } 84 | year *= 25; 85 | year += day / 1461; 86 | day %= 1461; 87 | year *= 4; 88 | if (day == 1460) { year += 3; day = 365; } 89 | else { year += day / 365; day %= 365; } 90 | day *= 10; 91 | if ((day + 5) / 306 >= 10) ++year; 92 | currentyear = year; 93 | flagneedcurrentyear = 0; 94 | } 95 | } 96 | 97 | /* UNIX ls does not show the year for dates in the last six months. */ 98 | /* So we have to guess the year. */ 99 | /* Apparently NetWare uses ``twelve months'' instead of ``six months''; ugh. */ 100 | /* Some versions of ls also fail to show the year for future dates. */ 101 | static long guesstai(long month,long mday) 102 | { 103 | long year; 104 | long t; 105 | 106 | initnow(); 107 | 108 | for (year = currentyear - 1;year < currentyear + 100;++year) { 109 | t = totai(year,month,mday); 110 | if (now - t < 350 * 86400) 111 | return t; 112 | } 113 | 114 | return -1; 115 | } 116 | 117 | static int check(char *buf,char *monthname) 118 | { 119 | if ((buf[0] != monthname[0]) && (buf[0] != monthname[0] - 32)) return 0; 120 | if ((buf[1] != monthname[1]) && (buf[1] != monthname[1] - 32)) return 0; 121 | if ((buf[2] != monthname[2]) && (buf[2] != monthname[2] - 32)) return 0; 122 | return 1; 123 | } 124 | 125 | static char *months[12] = { 126 | "jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec" 127 | } ; 128 | 129 | static int getmonth(char *buf,int len) 130 | { 131 | int i; 132 | if (len == 3) 133 | for (i = 0;i < 12;++i) 134 | if (check(buf,months[i])) return i; 135 | return -1; 136 | } 137 | 138 | static long getlong(char *buf,int len) 139 | { 140 | long u = 0; 141 | while (len-- > 0) 142 | u = u * 10 + (*buf++ - '0'); 143 | return u; 144 | } 145 | 146 | int ftpparse(struct ftpparse *fp,char *buf,int len) 147 | { 148 | int i; 149 | int j; 150 | int state; 151 | long size; 152 | long year; 153 | long month; 154 | long mday; 155 | long hour; 156 | long minute; 157 | 158 | fp->name = 0; 159 | fp->namelen = 0; 160 | fp->flagtrycwd = 0; 161 | fp->flagtryretr = 0; 162 | fp->sizetype = FTPPARSE_SIZE_UNKNOWN; 163 | fp->size = 0; 164 | fp->mtimetype = FTPPARSE_MTIME_UNKNOWN; 165 | fp->mtime = 0; 166 | fp->idtype = FTPPARSE_ID_UNKNOWN; 167 | fp->id = 0; 168 | fp->idlen = 0; 169 | 170 | if (len < 2) /* an empty name in EPLF, with no info, could be 2 chars */ 171 | return 0; 172 | 173 | switch(*buf) { 174 | /* see http://pobox.com/~djb/proto/eplf.txt */ 175 | /* "+i8388621.29609,m824255902,/,\tdev" */ 176 | /* "+i8388621.44468,m839956783,r,s10376,\tRFCEPLF" */ 177 | case '+': 178 | i = 1; 179 | for (j = 1;j < len;++j) { 180 | if (buf[j] == 9) { 181 | fp->name = buf + j + 1; 182 | fp->namelen = len - j - 1; 183 | return 1; 184 | } 185 | if (buf[j] == ',') { 186 | switch(buf[i]) { 187 | case '/': 188 | fp->flagtrycwd = 1; 189 | break; 190 | case 'r': 191 | fp->flagtryretr = 1; 192 | break; 193 | case 's': 194 | fp->sizetype = FTPPARSE_SIZE_BINARY; 195 | fp->size = getlong(buf + i + 1,j - i - 1); 196 | break; 197 | case 'm': 198 | fp->mtimetype = FTPPARSE_MTIME_LOCAL; 199 | initbase(); 200 | fp->mtime = base + getlong(buf + i + 1,j - i - 1); 201 | break; 202 | case 'i': 203 | fp->idtype = FTPPARSE_ID_FULL; 204 | fp->id = buf + i + 1; 205 | fp->idlen = j - i - 1; 206 | } 207 | i = j + 1; 208 | } 209 | } 210 | return 0; 211 | 212 | /* UNIX-style listing, without inum and without blocks */ 213 | /* "-rw-r--r-- 1 root other 531 Jan 29 03:26 README" */ 214 | /* "dr-xr-xr-x 2 root other 512 Apr 8 1994 etc" */ 215 | /* "dr-xr-xr-x 2 root 512 Apr 8 1994 etc" */ 216 | /* "lrwxrwxrwx 1 root other 7 Jan 25 00:17 bin -> usr/bin" */ 217 | /* Also produced by Microsoft's FTP servers for Windows: */ 218 | /* "---------- 1 owner group 1803128 Jul 10 10:18 ls-lR.Z" */ 219 | /* "d--------- 1 owner group 0 May 9 19:45 Softlib" */ 220 | /* Also WFTPD for MSDOS: */ 221 | /* "-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 message.ftp" */ 222 | /* Also NetWare: */ 223 | /* "d [R----F--] supervisor 512 Jan 16 18:53 login" */ 224 | /* "- [R----F--] rhesus 214059 Oct 20 15:27 cx.exe" */ 225 | /* Also NetPresenz for the Mac: */ 226 | /* "-------r-- 326 1391972 1392298 Nov 22 1995 MegaPhone.sit" */ 227 | /* "drwxrwxr-x folder 2 May 10 1996 network" */ 228 | case 'b': 229 | case 'c': 230 | case 'd': 231 | case 'l': 232 | case 'p': 233 | case 's': 234 | case '-': 235 | 236 | if (*buf == 'd') fp->flagtrycwd = 1; 237 | if (*buf == '-') fp->flagtryretr = 1; 238 | if (*buf == 'l') fp->flagtrycwd = fp->flagtryretr = 1; 239 | 240 | state = 1; 241 | i = 0; 242 | for (j = 1;j < len;++j) 243 | if ((buf[j] == ' ') && (buf[j - 1] != ' ')) { 244 | switch(state) { 245 | case 1: /* skipping perm */ 246 | state = 2; 247 | break; 248 | case 2: /* skipping nlink */ 249 | state = 3; 250 | if ((j - i == 6) && (buf[i] == 'f')) /* for NetPresenz */ 251 | state = 4; 252 | break; 253 | case 3: /* skipping uid */ 254 | state = 4; 255 | break; 256 | case 4: /* getting tentative size */ 257 | size = getlong(buf + i,j - i); 258 | state = 5; 259 | break; 260 | case 5: /* searching for month, otherwise getting tentative size */ 261 | month = getmonth(buf + i,j - i); 262 | if (month >= 0) 263 | state = 6; 264 | else 265 | size = getlong(buf + i,j - i); 266 | break; 267 | case 6: /* have size and month */ 268 | mday = getlong(buf + i,j - i); 269 | state = 7; 270 | break; 271 | case 7: /* have size, month, mday */ 272 | if ((j - i == 4) && (buf[i + 1] == ':')) { 273 | hour = getlong(buf + i,1); 274 | minute = getlong(buf + i + 2,2); 275 | fp->mtimetype = FTPPARSE_MTIME_REMOTEMINUTE; 276 | initbase(); 277 | fp->mtime = base + guesstai(month,mday) + hour * 3600 + minute * 60; 278 | } else if ((j - i == 5) && (buf[i + 2] == ':')) { 279 | hour = getlong(buf + i,2); 280 | minute = getlong(buf + i + 3,2); 281 | fp->mtimetype = FTPPARSE_MTIME_REMOTEMINUTE; 282 | initbase(); 283 | fp->mtime = base + guesstai(month,mday) + hour * 3600 + minute * 60; 284 | } 285 | else if (j - i >= 4) { 286 | year = getlong(buf + i,j - i); 287 | fp->mtimetype = FTPPARSE_MTIME_REMOTEDAY; 288 | initbase(); 289 | fp->mtime = base + totai(year,month,mday); 290 | } 291 | else 292 | return 0; 293 | fp->name = buf + j + 1; 294 | fp->namelen = len - j - 1; 295 | state = 8; 296 | break; 297 | case 8: /* twiddling thumbs */ 298 | break; 299 | } 300 | i = j + 1; 301 | while ((i < len) && (buf[i] == ' ')) ++i; 302 | } 303 | 304 | if (state != 8) 305 | return 0; 306 | 307 | fp->size = size; 308 | fp->sizetype = FTPPARSE_SIZE_BINARY; 309 | 310 | if (*buf == 'l') 311 | for (i = 0;i + 3 < fp->namelen;++i) 312 | if (fp->name[i] == ' ') 313 | if (fp->name[i + 1] == '-') 314 | if (fp->name[i + 2] == '>') 315 | if (fp->name[i + 3] == ' ') { 316 | fp->namelen = i; 317 | break; 318 | } 319 | 320 | /* eliminate extra NetWare spaces */ 321 | if ((buf[1] == ' ') || (buf[1] == '[')) 322 | if (fp->namelen > 3) 323 | if (fp->name[0] == ' ') 324 | if (fp->name[1] == ' ') 325 | if (fp->name[2] == ' ') { 326 | fp->name += 3; 327 | fp->namelen -= 3; 328 | } 329 | 330 | return 1; 331 | } 332 | 333 | /* MultiNet (some spaces removed from examples) */ 334 | /* "00README.TXT;1 2 30-DEC-1996 17:44 [SYSTEM] (RWED,RWED,RE,RE)" */ 335 | /* "CORE.DIR;1 1 8-SEP-1996 16:09 [SYSTEM] (RWE,RWE,RE,RE)" */ 336 | /* and non-MutliNet VMS: */ 337 | /* "CII-MANUAL.TEX;1 213/216 29-JAN-1996 03:33:12 [ANONYMOU,ANONYMOUS] (RWED,RWED,,)" */ 338 | for (i = 0;i < len;++i) 339 | if (buf[i] == ';') 340 | break; 341 | if (i < len) { 342 | fp->name = buf; 343 | fp->namelen = i; 344 | if (i > 4) 345 | if (buf[i - 4] == '.') 346 | if (buf[i - 3] == 'D') 347 | if (buf[i - 2] == 'I') 348 | if (buf[i - 1] == 'R') { 349 | fp->namelen -= 4; 350 | fp->flagtrycwd = 1; 351 | } 352 | if (!fp->flagtrycwd) 353 | fp->flagtryretr = 1; 354 | while (buf[i] != ' ') if (++i == len) return 0; 355 | while (buf[i] == ' ') if (++i == len) return 0; 356 | while (buf[i] != ' ') if (++i == len) return 0; 357 | while (buf[i] == ' ') if (++i == len) return 0; 358 | j = i; 359 | while (buf[j] != '-') if (++j == len) return 0; 360 | mday = getlong(buf + i,j - i); 361 | while (buf[j] == '-') if (++j == len) return 0; 362 | i = j; 363 | while (buf[j] != '-') if (++j == len) return 0; 364 | month = getmonth(buf + i,j - i); 365 | if (month < 0) return 0; 366 | while (buf[j] == '-') if (++j == len) return 0; 367 | i = j; 368 | while (buf[j] != ' ') if (++j == len) return 0; 369 | year = getlong(buf + i,j - i); 370 | while (buf[j] == ' ') if (++j == len) return 0; 371 | i = j; 372 | while (buf[j] != ':') if (++j == len) return 0; 373 | hour = getlong(buf + i,j - i); 374 | while (buf[j] == ':') if (++j == len) return 0; 375 | i = j; 376 | while ((buf[j] != ':') && (buf[j] != ' ')) if (++j == len) return 0; 377 | minute = getlong(buf + i,j - i); 378 | 379 | fp->mtimetype = FTPPARSE_MTIME_REMOTEMINUTE; 380 | initbase(); 381 | fp->mtime = base + totai(year,month,mday) + hour * 3600 + minute * 60; 382 | 383 | return 1; 384 | } 385 | 386 | /* MSDOS format */ 387 | /* 04-27-00 09:09PM licensed */ 388 | /* 07-18-00 10:16AM pub */ 389 | /* 04-14-00 03:47PM 589 readme.htm */ 390 | if ((*buf >= '0') && (*buf <= '9')) { 391 | i = 0; 392 | j = 0; 393 | while (buf[j] != '-') if (++j == len) return 0; 394 | month = getlong(buf + i,j - i) - 1; 395 | while (buf[j] == '-') if (++j == len) return 0; 396 | i = j; 397 | while (buf[j] != '-') if (++j == len) return 0; 398 | mday = getlong(buf + i,j - i); 399 | while (buf[j] == '-') if (++j == len) return 0; 400 | i = j; 401 | while (buf[j] != ' ') if (++j == len) return 0; 402 | year = getlong(buf + i,j - i); 403 | if (year < 50) year += 2000; 404 | if (year < 1000) year += 1900; 405 | while (buf[j] == ' ') if (++j == len) return 0; 406 | i = j; 407 | while (buf[j] != ':') if (++j == len) return 0; 408 | hour = getlong(buf + i,j - i); 409 | while (buf[j] == ':') if (++j == len) return 0; 410 | i = j; 411 | while ((buf[j] != 'A') && (buf[j] != 'P')) if (++j == len) return 0; 412 | minute = getlong(buf + i,j - i); 413 | if (hour == 12) hour = 0; 414 | if (buf[j] == 'A') if (++j == len) return 0; 415 | if (buf[j] == 'P') { hour += 12; if (++j == len) return 0; } 416 | if (buf[j] == 'M') if (++j == len) return 0; 417 | 418 | while (buf[j] == ' ') if (++j == len) return 0; 419 | if (buf[j] == '<') { 420 | fp->flagtrycwd = 1; 421 | while (buf[j] != ' ') if (++j == len) return 0; 422 | } 423 | else { 424 | i = j; 425 | while (buf[j] != ' ') if (++j == len) return 0; 426 | fp->size = getlong(buf + i,j - i); 427 | fp->sizetype = FTPPARSE_SIZE_BINARY; 428 | fp->flagtryretr = 1; 429 | } 430 | while (buf[j] == ' ') if (++j == len) return 0; 431 | 432 | fp->name = buf + j; 433 | fp->namelen = len - j; 434 | 435 | fp->mtimetype = FTPPARSE_MTIME_REMOTEMINUTE; 436 | initbase(); 437 | fp->mtime = base + totai(year,month,mday) + hour * 3600 + minute * 60; 438 | 439 | return 1; 440 | } 441 | 442 | /* Some useless lines, safely ignored: */ 443 | /* "Total of 11 Files, 10966 Blocks." (VMS) */ 444 | /* "total 14786" (UNIX) */ 445 | /* "DISK$ANONFTP:[ANONYMOUS]" (VMS) */ 446 | /* "Directory DISK$PCSA:[ANONYM]" (VMS) */ 447 | 448 | return 0; 449 | } 450 | -------------------------------------------------------------------------------- /objective-curl/src/ftpparse.h: -------------------------------------------------------------------------------- 1 | #ifndef FTPPARSE_H 2 | #define FTPPARSE_H 3 | 4 | /* 5 | ftpparse(&fp,buf,len) tries to parse one line of LIST output. 6 | 7 | The line is an array of len characters stored in buf. 8 | It should not include the terminating CR LF; so buf[len] is typically CR. 9 | 10 | If ftpparse() can't find a filename, it returns 0. 11 | 12 | If ftpparse() can find a filename, it fills in fp and returns 1. 13 | fp is a struct ftpparse, defined below. 14 | The name is an array of fp.namelen characters stored in fp.name; 15 | fp.name points somewhere within buf. 16 | */ 17 | 18 | struct ftpparse { 19 | char *name; /* not necessarily 0-terminated */ 20 | int namelen; 21 | int flagtrycwd; /* 0 if cwd is definitely pointless, 1 otherwise */ 22 | int flagtryretr; /* 0 if retr is definitely pointless, 1 otherwise */ 23 | int sizetype; 24 | long size; /* number of octets */ 25 | int mtimetype; 26 | time_t mtime; /* modification time */ 27 | int idtype; 28 | char *id; /* not necessarily 0-terminated */ 29 | int idlen; 30 | } ; 31 | 32 | #define FTPPARSE_SIZE_UNKNOWN 0 33 | #define FTPPARSE_SIZE_BINARY 1 /* size is the number of octets in TYPE I */ 34 | #define FTPPARSE_SIZE_ASCII 2 /* size is the number of octets in TYPE A */ 35 | 36 | #define FTPPARSE_MTIME_UNKNOWN 0 37 | #define FTPPARSE_MTIME_LOCAL 1 /* time is correct */ 38 | #define FTPPARSE_MTIME_REMOTEMINUTE 2 /* time zone and secs are unknown */ 39 | #define FTPPARSE_MTIME_REMOTEDAY 3 /* time zone and time of day are unknown */ 40 | /* 41 | When a time zone is unknown, it is assumed to be GMT. You may want 42 | to use localtime() for LOCAL times, along with an indication that the 43 | time is correct in the local time zone, and gmtime() for REMOTE* times. 44 | */ 45 | 46 | #define FTPPARSE_ID_UNKNOWN 0 47 | #define FTPPARSE_ID_FULL 1 /* unique identifier for files on this FTP server */ 48 | 49 | extern int ftpparse(struct ftpparse *,char *,int); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /objective-curl/src/objective-curl.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @header objective-curl.h 3 | @abstract Main framework include file. 4 | @discussion This header file includes all public classes referenced by the framework. 5 | */ 6 | 7 | #import "CurlS3.h" 8 | #import "CurlSFTP.h" 9 | #import "CurlUpload.h" 10 | #import "CurlUploadDelegate.h" 11 | #import "CurlFileTransfer.h" 12 | #import "CurlConnectionDelegate.h" 13 | #import "CurlRemoteFile.h" 14 | #import "CurlRemoteFolder.h" 15 | #import "CurlTransferStatus.h" 16 | #import "CurlClientType.h" --------------------------------------------------------------------------------