├── .gitignore ├── DAVKit.xcodeproj └── project.pbxproj ├── DAVKit_Prefix.pch ├── Info.plist ├── LICENSE.txt ├── README.markdown ├── Sources ├── Core │ ├── DAVBaseRequest.h │ ├── DAVBaseRequest.m │ ├── DAVCredentials.h │ ├── DAVCredentials.m │ ├── DAVKit.h │ ├── DAVListingParser.h │ ├── DAVListingParser.m │ ├── DAVRequest+Private.h │ ├── DAVRequest.h │ ├── DAVRequest.m │ ├── DAVRequestGroup.h │ ├── DAVRequestGroup.m │ ├── DAVRequests.h │ ├── DAVRequests.m │ ├── DAVResponseItem.h │ ├── DAVResponseItem.m │ ├── DAVSession.h │ └── DAVSession.m ├── ISO8601 │ ├── ISO8601DateFormatter.h │ ├── ISO8601DateFormatter.m │ └── LICENSE.txt ├── RFC1123 │ ├── NSDateRFC1123.h │ └── NSDateRFC1123.m └── Tests │ ├── AMkColTest.h │ ├── AMkColTest.m │ ├── BPutTest.h │ ├── BPutTest.m │ ├── CGetTest.h │ ├── CGetTest.m │ ├── DAVTest.h │ ├── DAVTest.m │ ├── DCopyTest.h │ ├── DCopyTest.m │ ├── EMoveTest.h │ ├── EMoveTest.m │ ├── FListTest.h │ ├── FListTest.m │ ├── GDeleteTest.h │ └── GDeleteTest.m └── Tests-Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | DAVTestSettings.h 2 | -------------------------------------------------------------------------------- /DAVKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; 11 | C9181BBC121DC31D0022E4AC /* DAVResponseItem.h in Headers */ = {isa = PBXBuildFile; fileRef = C9181BBA121DC31D0022E4AC /* DAVResponseItem.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | C9181BBD121DC31D0022E4AC /* DAVResponseItem.m in Sources */ = {isa = PBXBuildFile; fileRef = C9181BBB121DC31D0022E4AC /* DAVResponseItem.m */; }; 13 | C9A4E37E1406E12C004E4AEB /* DAVRequestGroup.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A4E37C1406E12C004E4AEB /* DAVRequestGroup.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | C9A4E37F1406E12C004E4AEB /* DAVRequestGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A4E37D1406E12C004E4AEB /* DAVRequestGroup.m */; }; 15 | C9A4E3A01406E9CF004E4AEB /* DAVBaseRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A4E39E1406E9CF004E4AEB /* DAVBaseRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; 16 | C9A4E3A11406E9CF004E4AEB /* DAVBaseRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A4E39F1406E9CF004E4AEB /* DAVBaseRequest.m */; }; 17 | C9FED59B121D989900DD1DFF /* DAVCredentials.h in Headers */ = {isa = PBXBuildFile; fileRef = C9FED58F121D989900DD1DFF /* DAVCredentials.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18 | C9FED59C121D989900DD1DFF /* DAVCredentials.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED590121D989900DD1DFF /* DAVCredentials.m */; }; 19 | C9FED59D121D989900DD1DFF /* DAVKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C9FED591121D989900DD1DFF /* DAVKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 20 | C9FED59E121D989900DD1DFF /* DAVListingParser.h in Headers */ = {isa = PBXBuildFile; fileRef = C9FED592121D989900DD1DFF /* DAVListingParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 21 | C9FED59F121D989900DD1DFF /* DAVListingParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED593121D989900DD1DFF /* DAVListingParser.m */; }; 22 | C9FED5A0121D989900DD1DFF /* DAVRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = C9FED594121D989900DD1DFF /* DAVRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; 23 | C9FED5A1121D989900DD1DFF /* DAVRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED595121D989900DD1DFF /* DAVRequest.m */; }; 24 | C9FED5A2121D989900DD1DFF /* DAVRequest+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C9FED596121D989900DD1DFF /* DAVRequest+Private.h */; }; 25 | C9FED5A3121D989900DD1DFF /* DAVRequests.h in Headers */ = {isa = PBXBuildFile; fileRef = C9FED597121D989900DD1DFF /* DAVRequests.h */; settings = {ATTRIBUTES = (Public, ); }; }; 26 | C9FED5A4121D989900DD1DFF /* DAVRequests.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED598121D989900DD1DFF /* DAVRequests.m */; }; 27 | C9FED5A5121D989900DD1DFF /* DAVSession.h in Headers */ = {isa = PBXBuildFile; fileRef = C9FED599121D989900DD1DFF /* DAVSession.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | C9FED5A6121D989900DD1DFF /* DAVSession.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED59A121D989900DD1DFF /* DAVSession.m */; }; 29 | C9FED5AF121D98B800DD1DFF /* ISO8601DateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = C9FED5AD121D98B800DD1DFF /* ISO8601DateFormatter.h */; }; 30 | C9FED5B0121D98B800DD1DFF /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5AE121D98B800DD1DFF /* ISO8601DateFormatter.m */; }; 31 | C9FED5C1121D98D600DD1DFF /* AMkColTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5B2121D98D600DD1DFF /* AMkColTest.m */; }; 32 | C9FED5C2121D98D600DD1DFF /* BPutTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5B4121D98D600DD1DFF /* BPutTest.m */; }; 33 | C9FED5C3121D98D600DD1DFF /* CGetTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5B6121D98D600DD1DFF /* CGetTest.m */; }; 34 | C9FED5C4121D98D600DD1DFF /* DAVTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5B8121D98D600DD1DFF /* DAVTest.m */; }; 35 | C9FED5C5121D98D600DD1DFF /* DCopyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5BA121D98D600DD1DFF /* DCopyTest.m */; }; 36 | C9FED5C6121D98D600DD1DFF /* EMoveTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5BC121D98D600DD1DFF /* EMoveTest.m */; }; 37 | C9FED5C7121D98D600DD1DFF /* FListTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5BE121D98D600DD1DFF /* FListTest.m */; }; 38 | C9FED5C8121D98D600DD1DFF /* GDeleteTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FED5C0121D98D600DD1DFF /* GDeleteTest.m */; }; 39 | C9FF7821121C7224001250C7 /* DAVKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* DAVKit.framework */; }; 40 | F94970ED132A093600713958 /* NSDateRFC1123.h in Headers */ = {isa = PBXBuildFile; fileRef = F94970EB132A093600713958 /* NSDateRFC1123.h */; }; 41 | F94970EE132A093600713958 /* NSDateRFC1123.m in Sources */ = {isa = PBXBuildFile; fileRef = F94970EC132A093600713958 /* NSDateRFC1123.m */; }; 42 | /* End PBXBuildFile section */ 43 | 44 | /* Begin PBXContainerItemProxy section */ 45 | C9FF77F2121C6F58001250C7 /* PBXContainerItemProxy */ = { 46 | isa = PBXContainerItemProxy; 47 | containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; 48 | proxyType = 1; 49 | remoteGlobalIDString = 8DC2EF4F0486A6940098B216; 50 | remoteInfo = DAVKit; 51 | }; 52 | /* End PBXContainerItemProxy section */ 53 | 54 | /* Begin PBXFileReference section */ 55 | 0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 56 | 0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 57 | 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 58 | 32DBCF5E0370ADEE00C91783 /* DAVKit_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DAVKit_Prefix.pch; sourceTree = ""; }; 59 | 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | 8DC2EF5B0486A6940098B216 /* DAVKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DAVKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | C9181BBA121DC31D0022E4AC /* DAVResponseItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVResponseItem.h; path = Sources/Core/DAVResponseItem.h; sourceTree = ""; }; 62 | C9181BBB121DC31D0022E4AC /* DAVResponseItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVResponseItem.m; path = Sources/Core/DAVResponseItem.m; sourceTree = ""; }; 63 | C939F7D313C67F6100925808 /* DAVTestSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVTestSettings.h; path = Sources/Tests/DAVTestSettings.h; sourceTree = ""; }; 64 | C9A4E37C1406E12C004E4AEB /* DAVRequestGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVRequestGroup.h; path = Sources/Core/DAVRequestGroup.h; sourceTree = ""; }; 65 | C9A4E37D1406E12C004E4AEB /* DAVRequestGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVRequestGroup.m; path = Sources/Core/DAVRequestGroup.m; sourceTree = ""; }; 66 | C9A4E39E1406E9CF004E4AEB /* DAVBaseRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVBaseRequest.h; path = Sources/Core/DAVBaseRequest.h; sourceTree = ""; }; 67 | C9A4E39F1406E9CF004E4AEB /* DAVBaseRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVBaseRequest.m; path = Sources/Core/DAVBaseRequest.m; sourceTree = ""; }; 68 | C9FED58F121D989900DD1DFF /* DAVCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVCredentials.h; path = Sources/Core/DAVCredentials.h; sourceTree = ""; }; 69 | C9FED590121D989900DD1DFF /* DAVCredentials.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVCredentials.m; path = Sources/Core/DAVCredentials.m; sourceTree = ""; }; 70 | C9FED591121D989900DD1DFF /* DAVKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVKit.h; path = Sources/Core/DAVKit.h; sourceTree = ""; }; 71 | C9FED592121D989900DD1DFF /* DAVListingParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVListingParser.h; path = Sources/Core/DAVListingParser.h; sourceTree = ""; }; 72 | C9FED593121D989900DD1DFF /* DAVListingParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVListingParser.m; path = Sources/Core/DAVListingParser.m; sourceTree = ""; }; 73 | C9FED594121D989900DD1DFF /* DAVRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVRequest.h; path = Sources/Core/DAVRequest.h; sourceTree = ""; }; 74 | C9FED595121D989900DD1DFF /* DAVRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVRequest.m; path = Sources/Core/DAVRequest.m; sourceTree = ""; }; 75 | C9FED596121D989900DD1DFF /* DAVRequest+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "DAVRequest+Private.h"; path = "Sources/Core/DAVRequest+Private.h"; sourceTree = ""; }; 76 | C9FED597121D989900DD1DFF /* DAVRequests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVRequests.h; path = Sources/Core/DAVRequests.h; sourceTree = ""; }; 77 | C9FED598121D989900DD1DFF /* DAVRequests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVRequests.m; path = Sources/Core/DAVRequests.m; sourceTree = ""; }; 78 | C9FED599121D989900DD1DFF /* DAVSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVSession.h; path = Sources/Core/DAVSession.h; sourceTree = ""; }; 79 | C9FED59A121D989900DD1DFF /* DAVSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVSession.m; path = Sources/Core/DAVSession.m; sourceTree = ""; }; 80 | C9FED5AD121D98B800DD1DFF /* ISO8601DateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ISO8601DateFormatter.h; path = Sources/ISO8601/ISO8601DateFormatter.h; sourceTree = ""; }; 81 | C9FED5AE121D98B800DD1DFF /* ISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ISO8601DateFormatter.m; path = Sources/ISO8601/ISO8601DateFormatter.m; sourceTree = ""; }; 82 | C9FED5B1121D98D600DD1DFF /* AMkColTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AMkColTest.h; path = Sources/Tests/AMkColTest.h; sourceTree = ""; }; 83 | C9FED5B2121D98D600DD1DFF /* AMkColTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AMkColTest.m; path = Sources/Tests/AMkColTest.m; sourceTree = ""; }; 84 | C9FED5B3121D98D600DD1DFF /* BPutTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BPutTest.h; path = Sources/Tests/BPutTest.h; sourceTree = ""; }; 85 | C9FED5B4121D98D600DD1DFF /* BPutTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BPutTest.m; path = Sources/Tests/BPutTest.m; sourceTree = ""; }; 86 | C9FED5B5121D98D600DD1DFF /* CGetTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CGetTest.h; path = Sources/Tests/CGetTest.h; sourceTree = ""; }; 87 | C9FED5B6121D98D600DD1DFF /* CGetTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CGetTest.m; path = Sources/Tests/CGetTest.m; sourceTree = ""; }; 88 | C9FED5B7121D98D600DD1DFF /* DAVTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DAVTest.h; path = Sources/Tests/DAVTest.h; sourceTree = ""; }; 89 | C9FED5B8121D98D600DD1DFF /* DAVTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DAVTest.m; path = Sources/Tests/DAVTest.m; sourceTree = ""; }; 90 | C9FED5B9121D98D600DD1DFF /* DCopyTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DCopyTest.h; path = Sources/Tests/DCopyTest.h; sourceTree = ""; }; 91 | C9FED5BA121D98D600DD1DFF /* DCopyTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DCopyTest.m; path = Sources/Tests/DCopyTest.m; sourceTree = ""; }; 92 | C9FED5BB121D98D600DD1DFF /* EMoveTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EMoveTest.h; path = Sources/Tests/EMoveTest.h; sourceTree = ""; }; 93 | C9FED5BC121D98D600DD1DFF /* EMoveTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EMoveTest.m; path = Sources/Tests/EMoveTest.m; sourceTree = ""; }; 94 | C9FED5BD121D98D600DD1DFF /* FListTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FListTest.h; path = Sources/Tests/FListTest.h; sourceTree = ""; }; 95 | C9FED5BE121D98D600DD1DFF /* FListTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FListTest.m; path = Sources/Tests/FListTest.m; sourceTree = ""; }; 96 | C9FED5BF121D98D600DD1DFF /* GDeleteTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GDeleteTest.h; path = Sources/Tests/GDeleteTest.h; sourceTree = ""; }; 97 | C9FED5C0121D98D600DD1DFF /* GDeleteTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GDeleteTest.m; path = Sources/Tests/GDeleteTest.m; sourceTree = ""; }; 98 | C9FF77EC121C6F51001250C7 /* Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 99 | C9FF77ED121C6F51001250C7 /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; 100 | D2F7E79907B2D74100F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 101 | F94970EB132A093600713958 /* NSDateRFC1123.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSDateRFC1123.h; sourceTree = ""; }; 102 | F94970EC132A093600713958 /* NSDateRFC1123.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDateRFC1123.m; sourceTree = ""; }; 103 | /* End PBXFileReference section */ 104 | 105 | /* Begin PBXFrameworksBuildPhase section */ 106 | 8DC2EF560486A6940098B216 /* Frameworks */ = { 107 | isa = PBXFrameworksBuildPhase; 108 | buildActionMask = 2147483647; 109 | files = ( 110 | 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */, 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | C9FF77E9121C6F51001250C7 /* Frameworks */ = { 115 | isa = PBXFrameworksBuildPhase; 116 | buildActionMask = 2147483647; 117 | files = ( 118 | C9FF7821121C7224001250C7 /* DAVKit.framework in Frameworks */, 119 | ); 120 | runOnlyForDeploymentPostprocessing = 0; 121 | }; 122 | /* End PBXFrameworksBuildPhase section */ 123 | 124 | /* Begin PBXGroup section */ 125 | 034768DFFF38A50411DB9C8B /* Products */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 8DC2EF5B0486A6940098B216 /* DAVKit.framework */, 129 | C9FF77EC121C6F51001250C7 /* Tests.octest */, 130 | ); 131 | name = Products; 132 | sourceTree = ""; 133 | }; 134 | 0867D691FE84028FC02AAC07 /* DAVKit */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 08FB77AEFE84172EC02AAC07 /* Classes */, 138 | 32C88DFF0371C24200C91783 /* Other Sources */, 139 | 089C1665FE841158C02AAC07 /* Resources */, 140 | 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, 141 | 034768DFFF38A50411DB9C8B /* Products */, 142 | ); 143 | name = DAVKit; 144 | sourceTree = ""; 145 | }; 146 | 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */, 150 | 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */, 151 | ); 152 | name = "External Frameworks and Libraries"; 153 | sourceTree = ""; 154 | }; 155 | 089C1665FE841158C02AAC07 /* Resources */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 8DC2EF5A0486A6940098B216 /* Info.plist */, 159 | C9FF77ED121C6F51001250C7 /* Tests-Info.plist */, 160 | ); 161 | name = Resources; 162 | sourceTree = ""; 163 | }; 164 | 08FB77AEFE84172EC02AAC07 /* Classes */ = { 165 | isa = PBXGroup; 166 | children = ( 167 | C9FF779F121C6BDF001250C7 /* Core */, 168 | C9FF7787121C6B8B001250C7 /* ISO8601 */, 169 | C9FF77A1121C6BF0001250C7 /* Private */, 170 | F94970EA132A093600713958 /* RFC1123 */, 171 | C9FF77A2121C6C1A001250C7 /* Tests */, 172 | C9FED591121D989900DD1DFF /* DAVKit.h */, 173 | ); 174 | name = Classes; 175 | sourceTree = ""; 176 | }; 177 | 1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */, 181 | ); 182 | name = "Linked Frameworks"; 183 | sourceTree = ""; 184 | }; 185 | 1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | 0867D6A5FE840307C02AAC07 /* AppKit.framework */, 189 | D2F7E79907B2D74100F64583 /* CoreData.framework */, 190 | 0867D69BFE84028FC02AAC07 /* Foundation.framework */, 191 | ); 192 | name = "Other Frameworks"; 193 | sourceTree = ""; 194 | }; 195 | 32C88DFF0371C24200C91783 /* Other Sources */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 32DBCF5E0370ADEE00C91783 /* DAVKit_Prefix.pch */, 199 | ); 200 | name = "Other Sources"; 201 | sourceTree = ""; 202 | }; 203 | C9FF7787121C6B8B001250C7 /* ISO8601 */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | C9FED5AD121D98B800DD1DFF /* ISO8601DateFormatter.h */, 207 | C9FED5AE121D98B800DD1DFF /* ISO8601DateFormatter.m */, 208 | ); 209 | name = ISO8601; 210 | sourceTree = ""; 211 | }; 212 | C9FF779F121C6BDF001250C7 /* Core */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | C9A4E39E1406E9CF004E4AEB /* DAVBaseRequest.h */, 216 | C9A4E39F1406E9CF004E4AEB /* DAVBaseRequest.m */, 217 | C9FED58F121D989900DD1DFF /* DAVCredentials.h */, 218 | C9FED590121D989900DD1DFF /* DAVCredentials.m */, 219 | C9FED594121D989900DD1DFF /* DAVRequest.h */, 220 | C9FED595121D989900DD1DFF /* DAVRequest.m */, 221 | C9A4E37C1406E12C004E4AEB /* DAVRequestGroup.h */, 222 | C9A4E37D1406E12C004E4AEB /* DAVRequestGroup.m */, 223 | C9FED597121D989900DD1DFF /* DAVRequests.h */, 224 | C9FED598121D989900DD1DFF /* DAVRequests.m */, 225 | C9181BBA121DC31D0022E4AC /* DAVResponseItem.h */, 226 | C9181BBB121DC31D0022E4AC /* DAVResponseItem.m */, 227 | C9FED599121D989900DD1DFF /* DAVSession.h */, 228 | C9FED59A121D989900DD1DFF /* DAVSession.m */, 229 | ); 230 | name = Core; 231 | sourceTree = ""; 232 | }; 233 | C9FF77A1121C6BF0001250C7 /* Private */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | C9FED592121D989900DD1DFF /* DAVListingParser.h */, 237 | C9FED593121D989900DD1DFF /* DAVListingParser.m */, 238 | C9FED596121D989900DD1DFF /* DAVRequest+Private.h */, 239 | ); 240 | name = Private; 241 | sourceTree = ""; 242 | }; 243 | C9FF77A2121C6C1A001250C7 /* Tests */ = { 244 | isa = PBXGroup; 245 | children = ( 246 | C939F7D313C67F6100925808 /* DAVTestSettings.h */, 247 | C9FED5B1121D98D600DD1DFF /* AMkColTest.h */, 248 | C9FED5B2121D98D600DD1DFF /* AMkColTest.m */, 249 | C9FED5B3121D98D600DD1DFF /* BPutTest.h */, 250 | C9FED5B4121D98D600DD1DFF /* BPutTest.m */, 251 | C9FED5B5121D98D600DD1DFF /* CGetTest.h */, 252 | C9FED5B6121D98D600DD1DFF /* CGetTest.m */, 253 | C9FED5B7121D98D600DD1DFF /* DAVTest.h */, 254 | C9FED5B8121D98D600DD1DFF /* DAVTest.m */, 255 | C9FED5B9121D98D600DD1DFF /* DCopyTest.h */, 256 | C9FED5BA121D98D600DD1DFF /* DCopyTest.m */, 257 | C9FED5BB121D98D600DD1DFF /* EMoveTest.h */, 258 | C9FED5BC121D98D600DD1DFF /* EMoveTest.m */, 259 | C9FED5BD121D98D600DD1DFF /* FListTest.h */, 260 | C9FED5BE121D98D600DD1DFF /* FListTest.m */, 261 | C9FED5BF121D98D600DD1DFF /* GDeleteTest.h */, 262 | C9FED5C0121D98D600DD1DFF /* GDeleteTest.m */, 263 | ); 264 | name = Tests; 265 | sourceTree = ""; 266 | }; 267 | F94970EA132A093600713958 /* RFC1123 */ = { 268 | isa = PBXGroup; 269 | children = ( 270 | F94970EB132A093600713958 /* NSDateRFC1123.h */, 271 | F94970EC132A093600713958 /* NSDateRFC1123.m */, 272 | ); 273 | name = RFC1123; 274 | path = Sources/RFC1123; 275 | sourceTree = ""; 276 | }; 277 | /* End PBXGroup section */ 278 | 279 | /* Begin PBXHeadersBuildPhase section */ 280 | 8DC2EF500486A6940098B216 /* Headers */ = { 281 | isa = PBXHeadersBuildPhase; 282 | buildActionMask = 2147483647; 283 | files = ( 284 | C9A4E3A01406E9CF004E4AEB /* DAVBaseRequest.h in Headers */, 285 | C9FED59B121D989900DD1DFF /* DAVCredentials.h in Headers */, 286 | C9FED59D121D989900DD1DFF /* DAVKit.h in Headers */, 287 | C9FED59E121D989900DD1DFF /* DAVListingParser.h in Headers */, 288 | C9FED5A0121D989900DD1DFF /* DAVRequest.h in Headers */, 289 | C9A4E37E1406E12C004E4AEB /* DAVRequestGroup.h in Headers */, 290 | C9FED5A2121D989900DD1DFF /* DAVRequest+Private.h in Headers */, 291 | C9FED5A3121D989900DD1DFF /* DAVRequests.h in Headers */, 292 | C9FED5A5121D989900DD1DFF /* DAVSession.h in Headers */, 293 | C9FED5AF121D98B800DD1DFF /* ISO8601DateFormatter.h in Headers */, 294 | C9181BBC121DC31D0022E4AC /* DAVResponseItem.h in Headers */, 295 | F94970ED132A093600713958 /* NSDateRFC1123.h in Headers */, 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | /* End PBXHeadersBuildPhase section */ 300 | 301 | /* Begin PBXNativeTarget section */ 302 | 8DC2EF4F0486A6940098B216 /* DAVKit */ = { 303 | isa = PBXNativeTarget; 304 | buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "DAVKit" */; 305 | buildPhases = ( 306 | 8DC2EF500486A6940098B216 /* Headers */, 307 | 8DC2EF520486A6940098B216 /* Resources */, 308 | 8DC2EF540486A6940098B216 /* Sources */, 309 | 8DC2EF560486A6940098B216 /* Frameworks */, 310 | ); 311 | buildRules = ( 312 | ); 313 | dependencies = ( 314 | ); 315 | name = DAVKit; 316 | productInstallPath = "$(HOME)/Library/Frameworks"; 317 | productName = DAVKit; 318 | productReference = 8DC2EF5B0486A6940098B216 /* DAVKit.framework */; 319 | productType = "com.apple.product-type.framework"; 320 | }; 321 | C9FF77EB121C6F51001250C7 /* Tests */ = { 322 | isa = PBXNativeTarget; 323 | buildConfigurationList = C9FF77F1121C6F52001250C7 /* Build configuration list for PBXNativeTarget "Tests" */; 324 | buildPhases = ( 325 | C9FF77E7121C6F51001250C7 /* Resources */, 326 | C9FF77E8121C6F51001250C7 /* Sources */, 327 | C9FF77E9121C6F51001250C7 /* Frameworks */, 328 | C9FF77EA121C6F51001250C7 /* ShellScript */, 329 | ); 330 | buildRules = ( 331 | ); 332 | dependencies = ( 333 | C9FF77F3121C6F58001250C7 /* PBXTargetDependency */, 334 | ); 335 | name = Tests; 336 | productName = Tests; 337 | productReference = C9FF77EC121C6F51001250C7 /* Tests.octest */; 338 | productType = "com.apple.product-type.bundle"; 339 | }; 340 | /* End PBXNativeTarget section */ 341 | 342 | /* Begin PBXProject section */ 343 | 0867D690FE84028FC02AAC07 /* Project object */ = { 344 | isa = PBXProject; 345 | attributes = { 346 | LastUpgradeCheck = 0420; 347 | }; 348 | buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "DAVKit" */; 349 | compatibilityVersion = "Xcode 3.2"; 350 | developmentRegion = English; 351 | hasScannedForEncodings = 1; 352 | knownRegions = ( 353 | English, 354 | Japanese, 355 | French, 356 | German, 357 | ); 358 | mainGroup = 0867D691FE84028FC02AAC07 /* DAVKit */; 359 | productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; 360 | projectDirPath = ""; 361 | projectRoot = ""; 362 | targets = ( 363 | 8DC2EF4F0486A6940098B216 /* DAVKit */, 364 | C9FF77EB121C6F51001250C7 /* Tests */, 365 | ); 366 | }; 367 | /* End PBXProject section */ 368 | 369 | /* Begin PBXResourcesBuildPhase section */ 370 | 8DC2EF520486A6940098B216 /* Resources */ = { 371 | isa = PBXResourcesBuildPhase; 372 | buildActionMask = 2147483647; 373 | files = ( 374 | ); 375 | runOnlyForDeploymentPostprocessing = 0; 376 | }; 377 | C9FF77E7121C6F51001250C7 /* Resources */ = { 378 | isa = PBXResourcesBuildPhase; 379 | buildActionMask = 2147483647; 380 | files = ( 381 | ); 382 | runOnlyForDeploymentPostprocessing = 0; 383 | }; 384 | /* End PBXResourcesBuildPhase section */ 385 | 386 | /* Begin PBXShellScriptBuildPhase section */ 387 | C9FF77EA121C6F51001250C7 /* ShellScript */ = { 388 | isa = PBXShellScriptBuildPhase; 389 | buildActionMask = 2147483647; 390 | files = ( 391 | ); 392 | inputPaths = ( 393 | ); 394 | outputPaths = ( 395 | ); 396 | runOnlyForDeploymentPostprocessing = 0; 397 | shellPath = /bin/sh; 398 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 399 | }; 400 | /* End PBXShellScriptBuildPhase section */ 401 | 402 | /* Begin PBXSourcesBuildPhase section */ 403 | 8DC2EF540486A6940098B216 /* Sources */ = { 404 | isa = PBXSourcesBuildPhase; 405 | buildActionMask = 2147483647; 406 | files = ( 407 | C9FED59C121D989900DD1DFF /* DAVCredentials.m in Sources */, 408 | C9FED59F121D989900DD1DFF /* DAVListingParser.m in Sources */, 409 | C9FED5A1121D989900DD1DFF /* DAVRequest.m in Sources */, 410 | C9FED5A4121D989900DD1DFF /* DAVRequests.m in Sources */, 411 | C9FED5A6121D989900DD1DFF /* DAVSession.m in Sources */, 412 | C9FED5B0121D98B800DD1DFF /* ISO8601DateFormatter.m in Sources */, 413 | C9181BBD121DC31D0022E4AC /* DAVResponseItem.m in Sources */, 414 | F94970EE132A093600713958 /* NSDateRFC1123.m in Sources */, 415 | C9A4E37F1406E12C004E4AEB /* DAVRequestGroup.m in Sources */, 416 | C9A4E3A11406E9CF004E4AEB /* DAVBaseRequest.m in Sources */, 417 | ); 418 | runOnlyForDeploymentPostprocessing = 0; 419 | }; 420 | C9FF77E8121C6F51001250C7 /* Sources */ = { 421 | isa = PBXSourcesBuildPhase; 422 | buildActionMask = 2147483647; 423 | files = ( 424 | C9FED5C1121D98D600DD1DFF /* AMkColTest.m in Sources */, 425 | C9FED5C2121D98D600DD1DFF /* BPutTest.m in Sources */, 426 | C9FED5C3121D98D600DD1DFF /* CGetTest.m in Sources */, 427 | C9FED5C4121D98D600DD1DFF /* DAVTest.m in Sources */, 428 | C9FED5C5121D98D600DD1DFF /* DCopyTest.m in Sources */, 429 | C9FED5C6121D98D600DD1DFF /* EMoveTest.m in Sources */, 430 | C9FED5C7121D98D600DD1DFF /* FListTest.m in Sources */, 431 | C9FED5C8121D98D600DD1DFF /* GDeleteTest.m in Sources */, 432 | ); 433 | runOnlyForDeploymentPostprocessing = 0; 434 | }; 435 | /* End PBXSourcesBuildPhase section */ 436 | 437 | /* Begin PBXTargetDependency section */ 438 | C9FF77F3121C6F58001250C7 /* PBXTargetDependency */ = { 439 | isa = PBXTargetDependency; 440 | target = 8DC2EF4F0486A6940098B216 /* DAVKit */; 441 | targetProxy = C9FF77F2121C6F58001250C7 /* PBXContainerItemProxy */; 442 | }; 443 | /* End PBXTargetDependency section */ 444 | 445 | /* Begin XCBuildConfiguration section */ 446 | 1DEB91AE08733DA50010E9CD /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ALWAYS_SEARCH_USER_PATHS = NO; 450 | CLANG_ENABLE_OBJC_ARC = YES; 451 | COPY_PHASE_STRIP = NO; 452 | DYLIB_COMPATIBILITY_VERSION = 1; 453 | DYLIB_CURRENT_VERSION = 1; 454 | FRAMEWORK_VERSION = A; 455 | GCC_DYNAMIC_NO_PIC = NO; 456 | GCC_MODEL_TUNING = G5; 457 | GCC_OPTIMIZATION_LEVEL = 0; 458 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 459 | GCC_PREFIX_HEADER = DAVKit_Prefix.pch; 460 | INFOPLIST_FILE = Info.plist; 461 | INSTALL_PATH = "@executable_path/../Frameworks"; 462 | PRODUCT_NAME = DAVKit; 463 | WRAPPER_EXTENSION = framework; 464 | }; 465 | name = Debug; 466 | }; 467 | 1DEB91AF08733DA50010E9CD /* Release */ = { 468 | isa = XCBuildConfiguration; 469 | buildSettings = { 470 | ALWAYS_SEARCH_USER_PATHS = NO; 471 | CLANG_ENABLE_OBJC_ARC = YES; 472 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 473 | DYLIB_COMPATIBILITY_VERSION = 1; 474 | DYLIB_CURRENT_VERSION = 1; 475 | FRAMEWORK_VERSION = A; 476 | GCC_MODEL_TUNING = G5; 477 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 478 | GCC_PREFIX_HEADER = DAVKit_Prefix.pch; 479 | INFOPLIST_FILE = Info.plist; 480 | INSTALL_PATH = "@executable_path/../Frameworks"; 481 | PRODUCT_NAME = DAVKit; 482 | WRAPPER_EXTENSION = framework; 483 | }; 484 | name = Release; 485 | }; 486 | 1DEB91B208733DA50010E9CD /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 490 | GCC_C_LANGUAGE_STANDARD = gnu99; 491 | GCC_OPTIMIZATION_LEVEL = 0; 492 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 493 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 494 | GCC_WARN_UNUSED_VARIABLE = YES; 495 | ONLY_ACTIVE_ARCH = YES; 496 | RUN_CLANG_STATIC_ANALYZER = YES; 497 | SDKROOT = macosx; 498 | }; 499 | name = Debug; 500 | }; 501 | 1DEB91B308733DA50010E9CD /* Release */ = { 502 | isa = XCBuildConfiguration; 503 | buildSettings = { 504 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 505 | GCC_C_LANGUAGE_STANDARD = gnu99; 506 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 507 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 508 | GCC_WARN_UNUSED_VARIABLE = YES; 509 | RUN_CLANG_STATIC_ANALYZER = YES; 510 | SDKROOT = macosx; 511 | }; 512 | name = Release; 513 | }; 514 | C9FF77EF121C6F52001250C7 /* Debug */ = { 515 | isa = XCBuildConfiguration; 516 | buildSettings = { 517 | ALWAYS_SEARCH_USER_PATHS = NO; 518 | COPY_PHASE_STRIP = NO; 519 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 520 | GCC_DYNAMIC_NO_PIC = NO; 521 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 522 | GCC_MODEL_TUNING = G5; 523 | GCC_OPTIMIZATION_LEVEL = 0; 524 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 525 | GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Cocoa.framework/Headers/Cocoa.h"; 526 | INFOPLIST_FILE = "Tests-Info.plist"; 527 | INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles"; 528 | OTHER_LDFLAGS = ( 529 | "-framework", 530 | Cocoa, 531 | "-framework", 532 | SenTestingKit, 533 | ); 534 | PRODUCT_NAME = Tests; 535 | WRAPPER_EXTENSION = octest; 536 | }; 537 | name = Debug; 538 | }; 539 | C9FF77F0121C6F52001250C7 /* Release */ = { 540 | isa = XCBuildConfiguration; 541 | buildSettings = { 542 | ALWAYS_SEARCH_USER_PATHS = NO; 543 | COPY_PHASE_STRIP = YES; 544 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 545 | FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; 546 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 547 | GCC_MODEL_TUNING = G5; 548 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 549 | GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Cocoa.framework/Headers/Cocoa.h"; 550 | INFOPLIST_FILE = "Tests-Info.plist"; 551 | INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles"; 552 | OTHER_LDFLAGS = ( 553 | "-framework", 554 | Cocoa, 555 | "-framework", 556 | SenTestingKit, 557 | ); 558 | PRODUCT_NAME = Tests; 559 | WRAPPER_EXTENSION = octest; 560 | ZERO_LINK = NO; 561 | }; 562 | name = Release; 563 | }; 564 | /* End XCBuildConfiguration section */ 565 | 566 | /* Begin XCConfigurationList section */ 567 | 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "DAVKit" */ = { 568 | isa = XCConfigurationList; 569 | buildConfigurations = ( 570 | 1DEB91AE08733DA50010E9CD /* Debug */, 571 | 1DEB91AF08733DA50010E9CD /* Release */, 572 | ); 573 | defaultConfigurationIsVisible = 0; 574 | defaultConfigurationName = Release; 575 | }; 576 | 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "DAVKit" */ = { 577 | isa = XCConfigurationList; 578 | buildConfigurations = ( 579 | 1DEB91B208733DA50010E9CD /* Debug */, 580 | 1DEB91B308733DA50010E9CD /* Release */, 581 | ); 582 | defaultConfigurationIsVisible = 0; 583 | defaultConfigurationName = Release; 584 | }; 585 | C9FF77F1121C6F52001250C7 /* Build configuration list for PBXNativeTarget "Tests" */ = { 586 | isa = XCConfigurationList; 587 | buildConfigurations = ( 588 | C9FF77EF121C6F52001250C7 /* Debug */, 589 | C9FF77F0121C6F52001250C7 /* Release */, 590 | ); 591 | defaultConfigurationIsVisible = 0; 592 | defaultConfigurationName = Release; 593 | }; 594 | /* End XCConfigurationList section */ 595 | }; 596 | rootObject = 0867D690FE84028FC02AAC07 /* Project object */; 597 | } 598 | -------------------------------------------------------------------------------- /DAVKit_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'DAVKit' target in the 'DAVKit' project. 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.MattRajca.${PRODUCT_NAME:rfc1034Identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Matt Rajca 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | DAVKit 2 | ====== 3 | 4 | DAVKit is a Cocoa framework for communicating with WebDAV servers. It supports downloading, uploading, copying, moving, and deleting files and folders, all asynchronously. By subclassing `DAVRequest`, you can extend the existing support for WebDAV requests to suit your own needs. Unit tests are also included for all supported requests. If DAVKit is missing something, please file an issue on the Issues page. Pull requests are also welcome. The DAVKit source tree is ARC-only as of 10/29/11. 5 | 6 | Basic Usage 7 | ----------- 8 | 9 | To get started, include the DAVKit framework in your Mac OS X application target per usual. To use DAVKit on iPhone, copy the contents of the Sources directory into your project. 10 | 11 | WebDAV requests are sent using the `DAVSession` class. Initialize `DAVSession` with a set of credentials and a root URL: 12 | 13 | DAVCredentials *credentials = [DAVCredentials credentialsWithUsername:@"USER" 14 | password:@"PASS"]; 15 | 16 | NSString *root = @"http://idisk.me.com/steve"; // don't include the trailing / (slash) 17 | 18 | DAVSession *session = [[DAVSession alloc] initWithRootURL:root 19 | credentials:credentials]; 20 | 21 | 22 | `DAVSession` acts like a queue, limiting the number of requests it can process at any point in time. The default is `2`. To enqueue a new WebDAV request, instantiate one of the subclasses of `DAVRequest` and pass it to `DAVSession` as shown below: 23 | 24 | [session enqueueRequest:subclassOfDAVRequest]; 25 | 26 | To receive callbacks when the state of the request changes, register yourself as the delegate of an instance of `DAVRequest` before enqueueing it. 27 | 28 | 29 | Unit Tests 30 | ---------- 31 | 32 | Before running the `Tests` target, fill in your WebDAV test server's information into the `HOST`, `USERNAME`, and `PASSWORD` #defines in `DAVTest.h`. The tests currently require network connectivity. 33 | 34 | Credits 35 | ------- 36 | 37 | Thanks to Peter Hosey for the ISO8601DateFormatter class! 38 | 39 | License 40 | ------- 41 | 42 | Copyright (c) 2010-2012 Matt Rajca 43 | 44 | Permission is hereby granted, free of charge, to any person obtaining a copy 45 | of this software and associated documentation files (the "Software"), to deal 46 | in the Software without restriction, including without limitation the rights 47 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 48 | copies of the Software, and to permit persons to whom the Software is 49 | furnished to do so, subject to the following conditions: 50 | 51 | The above copyright notice and this permission notice shall be included in 52 | all copies or substantial portions of the Software. 53 | 54 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 55 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 56 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 57 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 58 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 59 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 60 | THE SOFTWARE. 61 | -------------------------------------------------------------------------------- /Sources/Core/DAVBaseRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVBaseRequest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2011. All rights reserved. 6 | // 7 | 8 | @class DAVCredentials; 9 | 10 | @interface DAVBaseRequest : NSOperation { 11 | 12 | } 13 | 14 | @property (strong) NSURL *rootURL; 15 | @property (strong) DAVCredentials *credentials; 16 | @property (assign) BOOL allowUntrustedCertificate; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Sources/Core/DAVBaseRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVBaseRequest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2011. All rights reserved. 6 | // 7 | 8 | #import "DAVBaseRequest.h" 9 | 10 | @implementation DAVBaseRequest 11 | 12 | @synthesize rootURL = _rootURL, credentials = _credentials; 13 | @synthesize allowUntrustedCertificate = _allowUntrustedCertificate; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Sources/Core/DAVCredentials.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVCredentials.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | @interface DAVCredentials : NSObject { 9 | @private 10 | NSString *_username; 11 | NSString *_password; 12 | } 13 | 14 | @property (strong, readonly) NSString *username; 15 | @property (strong, readonly) NSString *password; 16 | 17 | + (id)credentialsWithUsername:(NSString *)username password:(NSString *)password; 18 | 19 | - (id)initWithUsername:(NSString *)username password:(NSString *)password; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Sources/Core/DAVCredentials.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVCredentials.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVCredentials.h" 9 | 10 | @implementation DAVCredentials 11 | 12 | @synthesize username = _username; 13 | @synthesize password = _password; 14 | 15 | + (id)credentialsWithUsername:(NSString *)username password:(NSString *)password { 16 | return [[[self class] alloc] initWithUsername:username password:password]; 17 | } 18 | 19 | - (id)initWithUsername:(NSString *)username password:(NSString *)password { 20 | NSParameterAssert(username != nil); 21 | NSParameterAssert(password != nil); 22 | 23 | self = [super init]; 24 | if (self) { 25 | _username = [username copy]; 26 | _password = [password copy]; 27 | } 28 | return self; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Sources/Core/DAVKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVKit.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import 14 | -------------------------------------------------------------------------------- /Sources/Core/DAVListingParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVListingParser.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | @class DAVResponseItem; 9 | 10 | @interface DAVListingParser : NSObject < NSXMLParserDelegate > { 11 | @private 12 | NSXMLParser *_parser; 13 | NSMutableString *_currentString; 14 | NSMutableArray *_items; 15 | DAVResponseItem *_currentItem; 16 | BOOL _inResponseType; 17 | } 18 | 19 | - (id)initWithData:(NSData *)data; 20 | 21 | - (NSArray *)parse:(NSError **)error; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Sources/Core/DAVListingParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVListingParser.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVListingParser.h" 9 | 10 | #import "DAVResponseItem.h" 11 | #import "ISO8601DateFormatter.h" 12 | #import "NSDateRFC1123.h" 13 | 14 | @interface DAVListingParser () 15 | 16 | - (NSDate *)_ISO8601DateWithString:(NSString *)aString; 17 | 18 | @end 19 | 20 | 21 | @implementation DAVListingParser 22 | 23 | - (id)initWithData:(NSData *)data { 24 | NSParameterAssert(data != nil); 25 | 26 | self = [super init]; 27 | if (self) { 28 | _items = [[NSMutableArray alloc] init]; 29 | 30 | _parser = [[NSXMLParser alloc] initWithData:data]; 31 | [_parser setDelegate:self]; 32 | [_parser setShouldProcessNamespaces:YES]; 33 | } 34 | return self; 35 | } 36 | 37 | - (NSArray *)parse:(NSError **)error { 38 | if (![_parser parse]) { 39 | if (error) { 40 | *error = [_parser parserError]; 41 | } 42 | 43 | return nil; 44 | } 45 | 46 | return [_items copy]; 47 | } 48 | 49 | - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { 50 | [_currentString appendString:string]; 51 | } 52 | 53 | - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 54 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 55 | attributes:(NSDictionary *)attributeDict { 56 | 57 | _currentString = [[NSMutableString alloc] init]; 58 | 59 | if ([elementName isEqualToString:@"response"]) { 60 | _currentItem = [[DAVResponseItem alloc] init]; 61 | } 62 | else if ([elementName isEqualToString:@"resourcetype"]) { 63 | _inResponseType = YES; 64 | } 65 | } 66 | 67 | - (NSDate *)_ISO8601DateWithString:(NSString *)aString { 68 | ISO8601DateFormatter *formatter = [[ISO8601DateFormatter alloc] init]; 69 | 70 | return [formatter dateFromString:aString]; 71 | } 72 | 73 | - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 74 | namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { 75 | 76 | if ([elementName isEqualToString:@"href"]) { 77 | _currentItem.href = [_currentString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 78 | } 79 | else if ([elementName isEqualToString:@"getcontentlength"]) { 80 | _currentItem.contentLength = [_currentString longLongValue]; 81 | } 82 | else if ([elementName isEqualToString:@"getcontenttype"]) { 83 | _currentItem.contentType = _currentString; 84 | } 85 | else if ([elementName isEqualToString:@"modificationdate"]) { 86 | _currentItem.modificationDate = [self _ISO8601DateWithString:_currentString]; 87 | } 88 | else if ([elementName isEqualToString:@"getlastmodified"]) { 89 | _currentItem.modificationDate = [NSDate dateFromRFC1123:_currentString]; 90 | } 91 | else if ([elementName isEqualToString:@"creationdate"]) { 92 | _currentItem.creationDate = [self _ISO8601DateWithString:_currentString]; 93 | } 94 | else if ([elementName isEqualToString:@"resourcetype"]) { 95 | _inResponseType = NO; 96 | } 97 | else if ([elementName isEqualToString:@"collection"] && _inResponseType) { 98 | _currentItem.resourceType = DAVResourceTypeCollection; 99 | } 100 | else if ([elementName isEqualToString:@"response"]) { 101 | [_items addObject:_currentItem]; 102 | 103 | _currentItem = nil; 104 | } 105 | 106 | _currentString = nil; 107 | } 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /Sources/Core/DAVRequest+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVRequest+Private.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | @class DAVSession; 9 | 10 | @interface DAVRequest (Private) 11 | 12 | - (NSMutableURLRequest *)newRequestWithPath:(NSString *)path method:(NSString *)method; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Core/DAVRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVRequest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVBaseRequest.h" 9 | 10 | @protocol DAVRequestDelegate; 11 | 12 | /* codes returned are HTTP status codes */ 13 | extern NSString *const DAVClientErrorDomain; 14 | 15 | @interface DAVRequest : DAVBaseRequest { 16 | @private 17 | NSString *_path; 18 | NSURLConnection *_connection; 19 | NSMutableData *_data; 20 | BOOL _done, _cancelled; 21 | BOOL _executing; 22 | } 23 | 24 | @property (strong, readonly) NSString *path; 25 | 26 | @property (weak) id < DAVRequestDelegate > delegate; 27 | 28 | - (id)initWithPath:(NSString *)aPath; 29 | 30 | - (NSURL *)concatenatedURLWithPath:(NSString *)aPath; 31 | 32 | /* must be overriden by subclasses */ 33 | - (NSURLRequest *)request; 34 | 35 | /* optional override */ 36 | - (id)resultForData:(NSData *)data; 37 | 38 | @end 39 | 40 | 41 | @protocol DAVRequestDelegate < NSObject > 42 | 43 | // The error can be a NSURLConnection error or a WebDAV error 44 | - (void)request:(DAVRequest *)aRequest didFailWithError:(NSError *)error; 45 | 46 | // The resulting object varies depending on the request type 47 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result; 48 | 49 | @optional 50 | 51 | - (void)requestDidBegin:(DAVRequest *)aRequest; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Sources/Core/DAVRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVRequest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVRequest.h" 9 | 10 | #import "DAVCredentials.h" 11 | #import "DAVSession.h" 12 | 13 | @interface DAVRequest () 14 | 15 | - (void)didFail:(NSError *)error; 16 | - (void)didFinish; 17 | 18 | @end 19 | 20 | 21 | @implementation DAVRequest 22 | 23 | NSString *const DAVClientErrorDomain = @"com.MattRajca.DAVKit.error"; 24 | 25 | #define DEFAULT_TIMEOUT 60 26 | 27 | @synthesize path = _path; 28 | @synthesize delegate = _delegate; 29 | 30 | - (id)initWithPath:(NSString *)aPath { 31 | self = [super init]; 32 | if (self) { 33 | _path = [aPath == nil ? @"" : aPath copy]; 34 | } 35 | return self; 36 | } 37 | 38 | - (NSURL *)concatenatedURLWithPath:(NSString *)aPath { 39 | NSParameterAssert(aPath != nil); 40 | 41 | return [self.rootURL URLByAppendingPathComponent:aPath]; 42 | } 43 | 44 | - (BOOL)isConcurrent { 45 | return YES; 46 | } 47 | 48 | - (BOOL)isExecuting { 49 | return _executing; 50 | } 51 | 52 | - (BOOL)isFinished { 53 | return _done; 54 | } 55 | 56 | - (BOOL)isCancelled { 57 | return _cancelled; 58 | } 59 | 60 | - (void)cancelWithCode:(NSInteger)code { 61 | [self willChangeValueForKey:@"isCancelled"]; 62 | 63 | [_connection cancel]; 64 | _cancelled = YES; 65 | 66 | [self didFail:[NSError errorWithDomain:DAVClientErrorDomain code:code userInfo:nil]]; 67 | 68 | [self didChangeValueForKey:@"isCancelled"]; 69 | } 70 | 71 | - (void)cancel { 72 | [self cancelWithCode:-1]; 73 | } 74 | 75 | - (void)start { 76 | if (![NSThread isMainThread]) { 77 | [self performSelectorOnMainThread:@selector(start) 78 | withObject:nil waitUntilDone:NO]; 79 | 80 | return; 81 | } 82 | 83 | [self willChangeValueForKey:@"isExecuting"]; 84 | 85 | _executing = YES; 86 | _connection = [NSURLConnection connectionWithRequest:[self request] 87 | delegate:self]; 88 | 89 | if ([_delegate respondsToSelector:@selector(requestDidBegin:)]) 90 | [_delegate requestDidBegin:self]; 91 | 92 | [self didChangeValueForKey:@"isExecuting"]; 93 | } 94 | 95 | - (NSURLRequest *)request { 96 | @throw [NSException exceptionWithName:NSInternalInconsistencyException 97 | reason:@"Subclasses of DAVRequest must override 'request'" 98 | userInfo:nil]; 99 | 100 | return nil; 101 | } 102 | 103 | - (id)resultForData:(NSData *)data { 104 | return nil; 105 | } 106 | 107 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 108 | if (!_data) { 109 | _data = [[NSMutableData alloc] init]; 110 | } 111 | 112 | [_data appendData:data]; 113 | } 114 | 115 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 116 | [self didFail:error]; 117 | } 118 | 119 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 120 | if ([response isKindOfClass:[NSHTTPURLResponse class]]) { 121 | NSInteger code = [(NSHTTPURLResponse *)response statusCode]; 122 | 123 | if (code >= 400) { 124 | [self cancelWithCode:code]; 125 | } 126 | } 127 | } 128 | 129 | - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { 130 | BOOL result = [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault] || 131 | [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic] || 132 | [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPDigest] || 133 | [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; 134 | 135 | return result; 136 | } 137 | 138 | - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { 139 | if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 140 | if (self.allowUntrustedCertificate) 141 | [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] 142 | forAuthenticationChallenge:challenge]; 143 | 144 | [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; 145 | } else { 146 | if ([challenge previousFailureCount] == 0) { 147 | NSURLCredential *credential = [NSURLCredential credentialWithUser:self.credentials.username 148 | password:self.credentials.password 149 | persistence:NSURLCredentialPersistenceNone]; 150 | 151 | [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; 152 | } else { 153 | // Wrong login/password 154 | [[challenge sender] cancelAuthenticationChallenge:challenge]; 155 | } 156 | } 157 | } 158 | 159 | - (void)didFail:(NSError *)error { 160 | if ([_delegate respondsToSelector:@selector(request:didFailWithError:)]) { 161 | [_delegate request:self didFailWithError:error]; 162 | } 163 | 164 | [self didFinish]; 165 | } 166 | 167 | - (void)didFinish { 168 | [self willChangeValueForKey:@"isExecuting"]; 169 | [self willChangeValueForKey:@"isFinished"]; 170 | 171 | _done = YES; 172 | _executing = NO; 173 | 174 | [self didChangeValueForKey:@"isExecuting"]; 175 | [self didChangeValueForKey:@"isFinished"]; 176 | } 177 | 178 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 179 | if ([_delegate respondsToSelector:@selector(request:didSucceedWithResult:)]) { 180 | id result = [self resultForData:_data]; 181 | 182 | [_delegate request:self didSucceedWithResult:result]; 183 | } 184 | 185 | [self didFinish]; 186 | } 187 | 188 | @end 189 | 190 | 191 | @implementation DAVRequest (Private) 192 | 193 | - (NSMutableURLRequest *)newRequestWithPath:(NSString *)path method:(NSString *)method { 194 | NSURL *url = [self concatenatedURLWithPath:path]; 195 | 196 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 197 | [request setHTTPMethod:method]; 198 | [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; 199 | [request setTimeoutInterval:DEFAULT_TIMEOUT]; 200 | 201 | return request; 202 | } 203 | 204 | @end 205 | -------------------------------------------------------------------------------- /Sources/Core/DAVRequestGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVRequestGroup.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2011. All rights reserved. 6 | // 7 | 8 | #import "DAVBaseRequest.h" 9 | #import "DAVRequest.h" 10 | 11 | @interface DAVRequestGroup : DAVBaseRequest < DAVRequestDelegate > { 12 | @private 13 | NSOperationQueue *_subQueue; 14 | NSMutableArray *_requests; 15 | BOOL _done, _executing; 16 | } 17 | 18 | /* The requests are executed serially; if one fails the remaining ones 19 | are cancelled */ 20 | 21 | - (id)initWithRequests:(NSArray *)requests; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Sources/Core/DAVRequestGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVRequestGroup.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2011. All rights reserved. 6 | // 7 | 8 | #import "DAVRequestGroup.h" 9 | 10 | @interface DAVRequestGroup () 11 | 12 | - (void)processNextRequest; 13 | - (void)didFinish; 14 | 15 | @end 16 | 17 | 18 | @implementation DAVRequestGroup 19 | 20 | - (id)init { 21 | NSAssert(0, @"The designated initializer -initWithRequests: should be used"); 22 | return nil; 23 | } 24 | 25 | - (id)initWithRequests:(NSArray *)requests { 26 | NSParameterAssert(requests != nil); 27 | 28 | self = [super init]; 29 | if (self) { 30 | _subQueue = [[NSOperationQueue alloc] init]; 31 | [_subQueue setMaxConcurrentOperationCount:1]; 32 | 33 | _requests = [requests mutableCopy]; 34 | } 35 | return self; 36 | } 37 | 38 | - (BOOL)isConcurrent { 39 | return YES; 40 | } 41 | 42 | - (BOOL)isExecuting { 43 | return _executing; 44 | } 45 | 46 | - (BOOL)isFinished { 47 | return _done; 48 | } 49 | 50 | - (void)start { 51 | if (![NSThread isMainThread]) { 52 | [self performSelectorOnMainThread:@selector(start) 53 | withObject:nil 54 | waitUntilDone:NO]; 55 | 56 | return; 57 | } 58 | 59 | [self willChangeValueForKey:@"isExecuting"]; 60 | 61 | _executing = YES; 62 | 63 | [self didChangeValueForKey:@"isExecuting"]; 64 | 65 | [self processNextRequest]; 66 | } 67 | 68 | - (void)processNextRequest { 69 | if ([_requests count]) { 70 | DAVRequest *request = [_requests objectAtIndex:0]; 71 | request.credentials = self.credentials; 72 | request.rootURL = self.rootURL; 73 | request.allowUntrustedCertificate = self.allowUntrustedCertificate; 74 | request.delegate = self; 75 | 76 | [_subQueue addOperation:request]; 77 | } 78 | else { 79 | [self didFinish]; 80 | } 81 | } 82 | 83 | - (void)didFinish { 84 | [self willChangeValueForKey:@"isExecuting"]; 85 | [self willChangeValueForKey:@"isFinished"]; 86 | 87 | _done = YES; 88 | _executing = NO; 89 | 90 | [self didChangeValueForKey:@"isExecuting"]; 91 | [self didChangeValueForKey:@"isFinished"]; 92 | } 93 | 94 | - (void)request:(DAVRequest *)aRequest didFailWithError:(NSError *)error { 95 | [self didFinish]; 96 | } 97 | 98 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result { 99 | [_requests removeObject:aRequest]; 100 | 101 | [self processNextRequest]; 102 | } 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /Sources/Core/DAVRequests.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVRequests.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVRequest.h" 9 | 10 | @interface DAVCopyRequest : DAVRequest { 11 | @private 12 | NSString *_destinationPath; 13 | BOOL _overwrite; 14 | } 15 | 16 | @property (copy) NSString *destinationPath; 17 | @property (assign) BOOL overwrite; 18 | 19 | @end 20 | 21 | @interface DAVDeleteRequest : DAVRequest { } 22 | @end 23 | 24 | @interface DAVGetRequest : DAVRequest { } 25 | @end 26 | 27 | @interface DAVListingRequest : DAVRequest { 28 | @private 29 | NSUInteger _depth; 30 | } 31 | 32 | @property (assign) NSUInteger depth; /* default is 1 */ 33 | 34 | @end 35 | 36 | @interface DAVMakeCollectionRequest : DAVRequest { } 37 | @end 38 | 39 | @interface DAVMoveRequest : DAVCopyRequest { } 40 | @end 41 | 42 | @interface DAVPutRequest : DAVRequest { 43 | @private 44 | NSData *_pdata; 45 | NSString *_MIMEType; 46 | } 47 | 48 | // Pass - [NSData dataWithContentsOfFile:] to upload a local file 49 | @property (strong) NSData *data; 50 | @property (copy) NSString *dataMIMEType; // defaults to application/octet-stream 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Sources/Core/DAVRequests.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVRequests.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVRequests.h" 9 | 10 | #import "DAVListingParser.h" 11 | #import "DAVRequest+Private.h" 12 | 13 | @implementation DAVCopyRequest 14 | 15 | @synthesize destinationPath = _destinationPath; 16 | @synthesize overwrite = _overwrite; 17 | 18 | - (NSString *)method { 19 | return @"COPY"; 20 | } 21 | 22 | - (NSURLRequest *)request { 23 | NSParameterAssert(_destinationPath != nil); 24 | 25 | NSURL *dp = [self concatenatedURLWithPath:_destinationPath]; 26 | 27 | NSMutableURLRequest *req = [self newRequestWithPath:self.path 28 | method:[self method]]; 29 | 30 | [req setValue:[dp absoluteString] forHTTPHeaderField:@"Destination"]; 31 | 32 | if (_overwrite) 33 | [req setValue:@"T" forHTTPHeaderField:@"Overwrite"]; 34 | else 35 | [req setValue:@"F" forHTTPHeaderField:@"Overwrite"]; 36 | 37 | return req; 38 | } 39 | 40 | @end 41 | 42 | 43 | @implementation DAVDeleteRequest 44 | 45 | - (NSURLRequest *)request { 46 | return [self newRequestWithPath:self.path method:@"DELETE"]; 47 | } 48 | 49 | @end 50 | 51 | 52 | @implementation DAVGetRequest 53 | 54 | - (NSURLRequest *)request { 55 | return [self newRequestWithPath:self.path method:@"GET"]; 56 | } 57 | 58 | - (id)resultForData:(NSData *)data { 59 | return data; 60 | } 61 | 62 | @end 63 | 64 | 65 | @implementation DAVListingRequest 66 | 67 | @synthesize depth = _depth; 68 | 69 | - (id)initWithPath:(NSString *)aPath { 70 | self = [super initWithPath:aPath]; 71 | if (self) { 72 | _depth = 1; 73 | } 74 | return self; 75 | } 76 | 77 | - (NSURLRequest *)request { 78 | NSMutableURLRequest *req = [self newRequestWithPath:self.path method:@"PROPFIND"]; 79 | 80 | if (_depth > 1) { 81 | [req setValue:@"infinity" forHTTPHeaderField:@"Depth"]; 82 | } 83 | else { 84 | [req setValue:[NSString stringWithFormat:@"%ld", _depth] forHTTPHeaderField:@"Depth"]; 85 | } 86 | 87 | [req setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"]; 88 | 89 | NSString *xml = @"\n" 90 | @""; 91 | 92 | [req setHTTPBody:[xml dataUsingEncoding:NSUTF8StringEncoding]]; 93 | 94 | return req; 95 | } 96 | 97 | - (id)resultForData:(NSData *)data { 98 | DAVListingParser *p = [[DAVListingParser alloc] initWithData:data]; 99 | 100 | NSError *error = nil; 101 | NSArray *items = [p parse:&error]; 102 | 103 | if (error) { 104 | #ifdef DEBUG 105 | NSLog(@"XML Parse error: %@", error); 106 | #endif 107 | } 108 | 109 | return items; 110 | } 111 | 112 | @end 113 | 114 | 115 | @implementation DAVMakeCollectionRequest 116 | 117 | - (NSURLRequest *)request { 118 | return [self newRequestWithPath:self.path method:@"MKCOL"]; 119 | } 120 | 121 | @end 122 | 123 | 124 | @implementation DAVMoveRequest 125 | 126 | - (NSString *)method { 127 | return @"MOVE"; 128 | } 129 | 130 | @end 131 | 132 | 133 | @implementation DAVPutRequest 134 | 135 | - (id)initWithPath:(NSString *)path { 136 | if ((self = [super initWithPath:path])) { 137 | self.dataMIMEType = @"application/octet-stream"; 138 | } 139 | return self; 140 | } 141 | 142 | @synthesize data = _pdata; 143 | @synthesize dataMIMEType = _MIMEType; 144 | 145 | - (NSURLRequest *)request { 146 | NSParameterAssert(_pdata != nil); 147 | 148 | NSString *len = [NSString stringWithFormat:@"%ld", [_pdata length]]; 149 | 150 | NSMutableURLRequest *req = [self newRequestWithPath:self.path method:@"PUT"]; 151 | [req setValue:[self dataMIMEType] forHTTPHeaderField:@"Content-Type"]; 152 | [req setValue:len forHTTPHeaderField:@"Content-Length"]; 153 | [req setHTTPBody:_pdata]; 154 | 155 | return req; 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /Sources/Core/DAVResponseItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVResponseItem.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | typedef enum { 9 | DAVResourceTypeUnspecified, 10 | DAVResourceTypeCollection 11 | } DAVResourceType; 12 | 13 | @interface DAVResponseItem : NSObject { 14 | @private 15 | NSString *href; 16 | NSDate *modificationDate; 17 | long long contentLength; 18 | NSString *contentType; 19 | NSDate *creationDate; 20 | DAVResourceType resourceType; 21 | } 22 | 23 | @property (copy) NSString *href; 24 | @property (strong) NSDate *modificationDate; 25 | @property (assign) long long contentLength; 26 | @property (strong) NSString *contentType; 27 | @property (strong) NSDate *creationDate; 28 | @property (assign) DAVResourceType resourceType; 29 | 30 | - (NSComparisonResult)compare:(DAVResponseItem *)item; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Sources/Core/DAVResponseItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVResponseItem.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVResponseItem.h" 9 | 10 | @implementation DAVResponseItem 11 | 12 | @synthesize href, modificationDate, contentLength, contentType; 13 | @synthesize creationDate, resourceType; 14 | 15 | - (id)init { 16 | self = [super init]; 17 | if (self) { 18 | resourceType = DAVResourceTypeUnspecified; 19 | } 20 | return self; 21 | } 22 | 23 | - (NSString *)description { 24 | return [NSString stringWithFormat:@"href = %@; modificationDate = %@; contentLength = %lld; " 25 | @"contentType = %@; creationDate = %@; resourceType = %d;", 26 | href, modificationDate, contentLength, contentType, 27 | creationDate, resourceType]; 28 | } 29 | 30 | - (NSComparisonResult)compare:(DAVResponseItem *)item { 31 | return [self.href compare:item.href]; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Sources/Core/DAVSession.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVSession.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | @class DAVCredentials; 9 | @class DAVBaseRequest; 10 | 11 | /* All paths are relative to the root of the server */ 12 | 13 | @interface DAVSession : NSObject { 14 | @private 15 | NSURL *_rootURL; 16 | DAVCredentials *_credentials; 17 | NSOperationQueue *_queue; 18 | } 19 | 20 | @property (strong, readonly) NSURL *rootURL; 21 | @property (strong, readonly) DAVCredentials *credentials; 22 | @property (assign) BOOL allowUntrustedCertificate; 23 | 24 | @property (readonly) NSUInteger requestCount; /* KVO compliant */ 25 | @property (assign) NSInteger maxConcurrentRequests; /* default is 2 */ 26 | 27 | /* 28 | The root URL should include a scheme and host, followed by any root paths 29 | **NOTE: omit the trailing slash (/)** 30 | Example: http://idisk.me.com/steve 31 | */ 32 | - (id)initWithRootURL:(NSURL *)url credentials:(DAVCredentials *)credentials; 33 | 34 | - (void)enqueueRequest:(DAVBaseRequest *)aRequest; 35 | - (void)cancelRequests; 36 | 37 | - (void)resetCredentialsCache; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Sources/Core/DAVSession.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVSession.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVSession.h" 9 | 10 | #import "DAVRequest.h" 11 | #import "DAVRequest+Private.h" 12 | #import "DAVRequests.h" 13 | 14 | @implementation DAVSession 15 | 16 | @synthesize rootURL = _rootURL; 17 | @synthesize credentials = _credentials; 18 | @synthesize allowUntrustedCertificate = _allowUntrustedCertificate; 19 | @dynamic requestCount, maxConcurrentRequests; 20 | 21 | #define DEFAULT_CONCURRENT_REQS 2 22 | 23 | - (id)initWithRootURL:(NSURL *)url credentials:(DAVCredentials *)credentials { 24 | NSParameterAssert(url != nil); 25 | 26 | if (!credentials) { 27 | #ifdef DEBUG 28 | NSLog(@"Warning: No credentials were provided. Servers rarely grant anonymous access"); 29 | #endif 30 | } 31 | 32 | self = [super init]; 33 | if (self) { 34 | _rootURL = [url copy]; 35 | _credentials = credentials; 36 | _allowUntrustedCertificate = NO; 37 | 38 | _queue = [[NSOperationQueue alloc] init]; 39 | [_queue setMaxConcurrentOperationCount:DEFAULT_CONCURRENT_REQS]; 40 | 41 | [_queue addObserver:self 42 | forKeyPath:@"operationCount" 43 | options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) 44 | context:NULL]; 45 | } 46 | return self; 47 | } 48 | 49 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 50 | if ([keyPath isEqualToString:@"operationCount"]) { 51 | [self willChangeValueForKey:@"requestCount"]; 52 | [self didChangeValueForKey:@"requestCount"]; 53 | } 54 | } 55 | 56 | - (NSUInteger)requestCount { 57 | return [_queue operationCount]; 58 | } 59 | 60 | - (NSInteger)maxConcurrentRequests { 61 | return [_queue maxConcurrentOperationCount]; 62 | } 63 | 64 | - (void)setMaxConcurrentRequests:(NSInteger)aVal { 65 | [_queue setMaxConcurrentOperationCount:aVal]; 66 | } 67 | 68 | - (void)enqueueRequest:(DAVBaseRequest *)aRequest { 69 | NSParameterAssert(aRequest != nil); 70 | 71 | aRequest.credentials = _credentials; 72 | aRequest.rootURL = _rootURL; 73 | aRequest.allowUntrustedCertificate = _allowUntrustedCertificate; 74 | 75 | [_queue addOperation:aRequest]; 76 | } 77 | 78 | - (void)cancelRequests { 79 | [_queue cancelAllOperations]; 80 | } 81 | 82 | - (void)resetCredentialsCache { 83 | // reset the credentials cache... 84 | NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials]; 85 | 86 | if ([credentialsDict count] > 0) { 87 | // the credentialsDict has NSURLProtectionSpace objs as keys and dicts of userName => NSURLCredential 88 | NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator]; 89 | id urlProtectionSpace; 90 | 91 | // iterate over all NSURLProtectionSpaces 92 | while ((urlProtectionSpace = [protectionSpaceEnumerator nextObject])) { 93 | NSEnumerator *userNameEnumerator = [[credentialsDict objectForKey:urlProtectionSpace] keyEnumerator]; 94 | id userName; 95 | 96 | // iterate over all usernames for this protection space, which are the keys for the actual NSURLCredentials 97 | while ((userName = [userNameEnumerator nextObject])) { 98 | NSURLCredential *cred = [[credentialsDict objectForKey:urlProtectionSpace] objectForKey:userName]; 99 | 100 | [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred 101 | forProtectionSpace:urlProtectionSpace]; 102 | } 103 | } 104 | } 105 | } 106 | 107 | - (void)dealloc { 108 | [_queue removeObserver:self forKeyPath:@"operationCount"]; 109 | } 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /Sources/ISO8601/ISO8601DateFormatter.h: -------------------------------------------------------------------------------- 1 | /*ISO8601DateFormatter.h 2 | * 3 | *Created by Peter Hosey on 2009-04-11. 4 | *Copyright 2009 Peter Hosey. All rights reserved. 5 | */ 6 | 7 | #import 8 | 9 | /*This class converts dates to and from ISO 8601 strings. A good introduction to ISO 8601: 10 | * 11 | *Parsing can be done strictly, or not. When you parse loosely, leading whitespace is ignored, as is anything after the date. 12 | *The loose parser will return an NSDate for this string: @" \t\r\n\f\t 2006-03-02!!!" 13 | *Leading non-whitespace will not be ignored; the string will be rejected, and nil returned. See the README that came with this addition. 14 | * 15 | *The strict parser will only accept a string if the date is the entire string. The above string would be rejected immediately, solely on these grounds. 16 | *Also, the loose parser provides some extensions that the strict parser doesn't. 17 | *For example, the standard says for "-DDD" (an ordinal date in the implied year) that the logical representation (meaning, hierarchically) would be "--DDD", but because that extra hyphen is "superfluous", it was omitted. 18 | *The loose parser will accept the extra hyphen; the strict parser will not. 19 | *A full list of these extensions is in the README file. 20 | */ 21 | 22 | /*The format to either expect or produce. 23 | *Calendar format is YYYY-MM-DD. 24 | *Ordinal format is YYYY-DDD, where DDD ranges from 1 to 366; for example, 2009-32 is 2009-02-01. 25 | *Week format is YYYY-Www-D, where ww ranges from 1 to 53 (the 'W' is literal) and D ranges from 1 to 7; for example, 2009-W05-07. 26 | */ 27 | enum { 28 | ISO8601DateFormatCalendar, 29 | ISO8601DateFormatOrdinal, 30 | ISO8601DateFormatWeek, 31 | }; 32 | typedef NSUInteger ISO8601DateFormat; 33 | 34 | //The default separator for time values. Currently, this is ':'. 35 | extern unichar ISO8601DefaultTimeSeparatorCharacter; 36 | 37 | @interface ISO8601DateFormatter: NSFormatter 38 | { 39 | NSString *lastUsedFormatString; 40 | NSDateFormatter *unparsingFormatter; 41 | 42 | NSCalendar *parsingCalendar, *unparsingCalendar; 43 | 44 | NSTimeZone *defaultTimeZone; 45 | ISO8601DateFormat format; 46 | unichar timeSeparator; 47 | BOOL includeTime; 48 | BOOL parsesStrictly; 49 | } 50 | 51 | //Call this if you get a memory warning. 52 | + (void) purgeGlobalCaches; 53 | 54 | @property(nonatomic, retain) NSTimeZone *defaultTimeZone; 55 | 56 | #pragma mark Parsing 57 | 58 | //As a formatter, this object converts strings to dates. 59 | 60 | @property BOOL parsesStrictly; 61 | 62 | - (NSDateComponents *) dateComponentsFromString:(NSString *)string; 63 | - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone; 64 | - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange; 65 | 66 | - (NSDate *) dateFromString:(NSString *)string; 67 | - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone; 68 | - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange; 69 | 70 | #pragma mark Unparsing 71 | 72 | @property ISO8601DateFormat format; 73 | @property BOOL includeTime; 74 | @property unichar timeSeparator; 75 | 76 | - (NSString *) stringFromDate:(NSDate *)date; 77 | - (NSString *) stringFromDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone; 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /Sources/ISO8601/ISO8601DateFormatter.m: -------------------------------------------------------------------------------- 1 | /*ISO8601DateFormatter.m 2 | * 3 | *Created by Peter Hosey on 2009-04-11. 4 | *Copyright 2009 Peter Hosey. All rights reserved. 5 | */ 6 | 7 | #import 8 | #import "ISO8601DateFormatter.h" 9 | 10 | #ifndef DEFAULT_TIME_SEPARATOR 11 | # define DEFAULT_TIME_SEPARATOR ':' 12 | #endif 13 | unichar ISO8601DefaultTimeSeparatorCharacter = DEFAULT_TIME_SEPARATOR; 14 | 15 | //Unicode date formats. 16 | #define ISO_CALENDAR_DATE_FORMAT @"yyyy-MM-dd" 17 | //#define ISO_WEEK_DATE_FORMAT @"YYYY-'W'ww-ee" //Doesn't actually work because NSDateComponents counts the weekday starting at 1. 18 | #define ISO_ORDINAL_DATE_FORMAT @"yyyy-DDD" 19 | #define ISO_TIME_FORMAT @"HH:mm:ss" 20 | #define ISO_TIME_WITH_TIMEZONE_FORMAT ISO_TIME_FORMAT @"Z" 21 | //printf formats. 22 | #define ISO_TIMEZONE_UTC_FORMAT @"Z" 23 | #define ISO_TIMEZONE_OFFSET_FORMAT @"%+.2d%.2d" 24 | 25 | @interface ISO8601DateFormatter(UnparsingPrivate) 26 | 27 | - (NSString *) replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep; 28 | 29 | - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat timeZone:(NSTimeZone *)timeZone; 30 | - (NSString *) weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone; 31 | 32 | @end 33 | 34 | static NSMutableDictionary *timeZonesByOffset; 35 | 36 | @implementation ISO8601DateFormatter 37 | 38 | + (void) initialize { 39 | if (!timeZonesByOffset) { 40 | timeZonesByOffset = [[NSMutableDictionary alloc] init]; 41 | } 42 | } 43 | 44 | + (void) purgeGlobalCaches { 45 | timeZonesByOffset = nil; 46 | } 47 | 48 | - (NSCalendar *) makeCalendarWithDesiredConfiguration { 49 | NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; 50 | calendar.firstWeekday = 2; //Monday 51 | calendar.timeZone = [NSTimeZone defaultTimeZone]; 52 | return calendar; 53 | } 54 | 55 | - (id) init { 56 | if ((self = [super init])) { 57 | parsingCalendar = [self makeCalendarWithDesiredConfiguration]; 58 | unparsingCalendar = [self makeCalendarWithDesiredConfiguration]; 59 | 60 | format = ISO8601DateFormatCalendar; 61 | timeSeparator = ISO8601DefaultTimeSeparatorCharacter; 62 | includeTime = NO; 63 | parsesStrictly = NO; 64 | } 65 | return self; 66 | } 67 | 68 | @synthesize defaultTimeZone; 69 | 70 | - (void) setDefaultTimeZone:(NSTimeZone *)tz { 71 | if (defaultTimeZone != tz) { 72 | defaultTimeZone = tz; 73 | 74 | unparsingCalendar.timeZone = defaultTimeZone; 75 | } 76 | } 77 | 78 | //The following properties are only here because GCC doesn't like @synthesize in category implementations. 79 | 80 | #pragma mark Parsing 81 | 82 | @synthesize parsesStrictly; 83 | 84 | static NSUInteger read_segment(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits); 85 | static NSUInteger read_segment_4digits(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits); 86 | static NSUInteger read_segment_2digits(const unsigned char *str, const unsigned char **next); 87 | static double read_double(const unsigned char *str, const unsigned char **next); 88 | static BOOL is_leap_year(NSUInteger year); 89 | 90 | /*Valid ISO 8601 date formats: 91 | * 92 | *YYYYMMDD 93 | *YYYY-MM-DD 94 | *YYYY-MM 95 | *YYYY 96 | *YY //century 97 | * //Implied century: YY is 00-99 98 | * YYMMDD 99 | * YY-MM-DD 100 | * -YYMM 101 | * -YY-MM 102 | * -YY 103 | * //Implied year 104 | * --MMDD 105 | * --MM-DD 106 | * --MM 107 | * //Implied year and month 108 | * ---DD 109 | * //Ordinal dates: DDD is the number of the day in the year (1-366) 110 | *YYYYDDD 111 | *YYYY-DDD 112 | * YYDDD 113 | * YY-DDD 114 | * -DDD 115 | * //Week-based dates: ww is the number of the week, and d is the number (1-7) of the day in the week 116 | *yyyyWwwd 117 | *yyyy-Www-d 118 | *yyyyWww 119 | *yyyy-Www 120 | *yyWwwd 121 | *yy-Www-d 122 | *yyWww 123 | *yy-Www 124 | * //Year of the implied decade 125 | *-yWwwd 126 | *-y-Www-d 127 | *-yWww 128 | *-y-Www 129 | * //Week and day of implied year 130 | * -Wwwd 131 | * -Www-d 132 | * //Week only of implied year 133 | * -Www 134 | * //Day only of implied week 135 | * -W-d 136 | */ 137 | 138 | - (NSDateComponents *) dateComponentsFromString:(NSString *)string { 139 | return [self dateComponentsFromString:string timeZone:NULL]; 140 | } 141 | - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone { 142 | return [self dateComponentsFromString:string timeZone:outTimeZone range:NULL]; 143 | } 144 | - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange { 145 | NSDate *now = [NSDate date]; 146 | 147 | NSDateComponents *components = [[NSDateComponents alloc] init]; 148 | NSDateComponents *nowComponents = [parsingCalendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now]; 149 | 150 | NSUInteger 151 | //Date 152 | year, 153 | month_or_week = 0U, 154 | day = 0U, 155 | //Time 156 | hour = 0U; 157 | NSTimeInterval 158 | minute = 0.0, 159 | second = 0.0; 160 | //Time zone 161 | NSInteger tz_hour = 0; 162 | NSInteger tz_minute = 0; 163 | 164 | enum { 165 | monthAndDate, 166 | week, 167 | dateOnly 168 | } dateSpecification = monthAndDate; 169 | 170 | BOOL strict = self.parsesStrictly; 171 | unichar timeSep = self.timeSeparator; 172 | 173 | if (strict) timeSep = ISO8601DefaultTimeSeparatorCharacter; 174 | NSAssert(timeSep != '\0', @"Time separator must not be NUL."); 175 | 176 | BOOL isValidDate = ([string length] > 0U); 177 | NSTimeZone *timeZone = nil; 178 | 179 | const unsigned char *ch = (const unsigned char *)[string UTF8String]; 180 | 181 | NSRange range = { 0U, 0U }; 182 | const unsigned char *start_of_date = NULL; 183 | if (strict && isspace(*ch)) { 184 | range.location = NSNotFound; 185 | isValidDate = NO; 186 | } else { 187 | //Skip leading whitespace. 188 | NSUInteger i = 0U; 189 | for(NSUInteger len = strlen((const char *)ch); i < len; ++i) { 190 | if (!isspace(ch[i])) 191 | break; 192 | } 193 | 194 | range.location = i; 195 | ch += i; 196 | start_of_date = ch; 197 | 198 | NSUInteger segment; 199 | NSUInteger num_leading_hyphens = 0U, num_digits = 0U; 200 | 201 | if (*ch == 'T') { 202 | //There is no date here, only a time. Set the date to now; then we'll parse the time. 203 | isValidDate = isdigit(*++ch); 204 | 205 | year = nowComponents.year; 206 | month_or_week = nowComponents.month; 207 | day = nowComponents.day; 208 | } else { 209 | while(*ch == '-') { 210 | ++num_leading_hyphens; 211 | ++ch; 212 | } 213 | 214 | segment = read_segment(ch, &ch, &num_digits); 215 | switch(num_digits) { 216 | case 0: 217 | if (*ch == 'W') { 218 | if ((ch[1] == '-') && isdigit(ch[2]) && ((num_leading_hyphens == 1U) || ((num_leading_hyphens == 2U) && !strict))) { 219 | year = nowComponents.year; 220 | month_or_week = 1U; 221 | ch += 2; 222 | goto parseDayAfterWeek; 223 | } else if (num_leading_hyphens == 1U) { 224 | year = nowComponents.year; 225 | goto parseWeekAndDay; 226 | } else 227 | isValidDate = NO; 228 | } else 229 | isValidDate = NO; 230 | break; 231 | 232 | case 8: //YYYY MM DD 233 | if (num_leading_hyphens > 0U) 234 | isValidDate = NO; 235 | else { 236 | day = segment % 100U; 237 | segment /= 100U; 238 | month_or_week = segment % 100U; 239 | year = segment / 100U; 240 | } 241 | break; 242 | 243 | case 6: //YYMMDD (implicit century) 244 | if (num_leading_hyphens > 0U) 245 | isValidDate = NO; 246 | else { 247 | day = segment % 100U; 248 | segment /= 100U; 249 | month_or_week = segment % 100U; 250 | year = nowComponents.year; 251 | year -= (year % 100U); 252 | year += segment / 100U; 253 | } 254 | break; 255 | 256 | case 4: 257 | switch(num_leading_hyphens) { 258 | case 0: //YYYY 259 | year = segment; 260 | 261 | if (*ch == '-') ++ch; 262 | 263 | if (!isdigit(*ch)) { 264 | if (*ch == 'W') 265 | goto parseWeekAndDay; 266 | else 267 | month_or_week = day = 1U; 268 | } else { 269 | segment = read_segment(ch, &ch, &num_digits); 270 | switch(num_digits) { 271 | case 4: //MMDD 272 | day = segment % 100U; 273 | month_or_week = segment / 100U; 274 | break; 275 | 276 | case 2: //MM 277 | month_or_week = segment; 278 | 279 | if (*ch == '-') ++ch; 280 | if (!isdigit(*ch)) 281 | day = 1U; 282 | else 283 | day = read_segment(ch, &ch, NULL); 284 | break; 285 | 286 | case 3: //DDD 287 | day = segment % 1000U; 288 | dateSpecification = dateOnly; 289 | if (strict && (day > (365U + is_leap_year(year)))) 290 | isValidDate = NO; 291 | break; 292 | 293 | default: 294 | isValidDate = NO; 295 | } 296 | } 297 | break; 298 | 299 | case 1: //YYMM 300 | month_or_week = segment % 100U; 301 | year = segment / 100U; 302 | 303 | if (*ch == '-') ++ch; 304 | if (!isdigit(*ch)) 305 | day = 1U; 306 | else 307 | day = read_segment(ch, &ch, NULL); 308 | 309 | break; 310 | 311 | case 2: //MMDD 312 | day = segment % 100U; 313 | month_or_week = segment / 100U; 314 | year = nowComponents.year; 315 | 316 | break; 317 | 318 | default: 319 | isValidDate = NO; 320 | } //switch(num_leading_hyphens) (4 digits) 321 | break; 322 | 323 | case 1: 324 | if (strict) { 325 | //Two digits only - never just one. 326 | if (num_leading_hyphens == 1U) { 327 | if (*ch == '-') ++ch; 328 | if (*++ch == 'W') { 329 | year = nowComponents.year; 330 | year -= (year % 10U); 331 | year += segment; 332 | goto parseWeekAndDay; 333 | } else 334 | isValidDate = NO; 335 | } else 336 | isValidDate = NO; 337 | break; 338 | } 339 | case 2: 340 | switch(num_leading_hyphens) { 341 | case 0: 342 | if (*ch == '-') { 343 | //Implicit century 344 | year = nowComponents.year; 345 | year -= (year % 100U); 346 | year += segment; 347 | 348 | if (*++ch == 'W') 349 | goto parseWeekAndDay; 350 | else if (!isdigit(*ch)) { 351 | goto centuryOnly; 352 | } else { 353 | //Get month and/or date. 354 | segment = read_segment_4digits(ch, &ch, &num_digits); 355 | NSLog(@"(%@) parsing month; segment is %lu and ch is %s", string, (unsigned long)segment, ch); 356 | switch(num_digits) { 357 | case 4: //YY-MMDD 358 | day = segment % 100U; 359 | month_or_week = segment / 100U; 360 | break; 361 | 362 | case 1: //YY-M; YY-M-DD (extension) 363 | if (strict) { 364 | isValidDate = NO; 365 | break; 366 | } 367 | case 2: //YY-MM; YY-MM-DD 368 | month_or_week = segment; 369 | if (*ch == '-') { 370 | if (isdigit(*++ch)) 371 | day = read_segment_2digits(ch, &ch); 372 | else 373 | day = 1U; 374 | } else 375 | day = 1U; 376 | break; 377 | 378 | case 3: //Ordinal date. 379 | day = segment; 380 | dateSpecification = dateOnly; 381 | break; 382 | } 383 | } 384 | } else if (*ch == 'W') { 385 | year = nowComponents.year; 386 | year -= (year % 100U); 387 | year += segment; 388 | 389 | parseWeekAndDay: //*ch should be 'W' here. 390 | if (!isdigit(*++ch)) { 391 | //Not really a week-based date; just a year followed by '-W'. 392 | if (strict) 393 | isValidDate = NO; 394 | else 395 | month_or_week = day = 1U; 396 | } else { 397 | month_or_week = read_segment_2digits(ch, &ch); 398 | if (*ch == '-') ++ch; 399 | parseDayAfterWeek: 400 | day = isdigit(*ch) ? read_segment_2digits(ch, &ch) : 1U; 401 | dateSpecification = week; 402 | } 403 | } else { 404 | //Century only. Assume current year. 405 | centuryOnly: 406 | year = segment * 100U + nowComponents.year % 100U; 407 | month_or_week = day = 1U; 408 | } 409 | break; 410 | 411 | case 1:; //-YY; -YY-MM (implicit century) 412 | NSLog(@"(%@) found %lu digits and one hyphen, so this is either -YY or -YY-MM; segment (year) is %lu", string, (unsigned long)num_digits, (unsigned long)segment); 413 | NSUInteger current_year = nowComponents.year; 414 | NSUInteger current_century = (current_year % 100U); 415 | year = segment + (current_year - current_century); 416 | if (num_digits == 1U) //implied decade 417 | year += current_century - (current_year % 10U); 418 | 419 | if (*ch == '-') { 420 | ++ch; 421 | month_or_week = read_segment_2digits(ch, &ch); 422 | NSLog(@"(%@) month is %lu", string, (unsigned long)month_or_week); 423 | } 424 | 425 | day = 1U; 426 | break; 427 | 428 | case 2: //--MM; --MM-DD 429 | year = nowComponents.year; 430 | month_or_week = segment; 431 | if (*ch == '-') { 432 | ++ch; 433 | day = read_segment_2digits(ch, &ch); 434 | } 435 | break; 436 | 437 | case 3: //---DD 438 | year = nowComponents.year; 439 | month_or_week = nowComponents.month; 440 | day = segment; 441 | break; 442 | 443 | default: 444 | isValidDate = NO; 445 | } //switch(num_leading_hyphens) (2 digits) 446 | break; 447 | 448 | case 7: //YYYY DDD (ordinal date) 449 | if (num_leading_hyphens > 0U) 450 | isValidDate = NO; 451 | else { 452 | day = segment % 1000U; 453 | year = segment / 1000U; 454 | dateSpecification = dateOnly; 455 | if (strict && (day > (365U + is_leap_year(year)))) 456 | isValidDate = NO; 457 | } 458 | break; 459 | 460 | case 3: //--DDD (ordinal date, implicit year) 461 | //Technically, the standard only allows one hyphen. But it says that two hyphens is the logical implementation, and one was dropped for brevity. So I have chosen to allow the missing hyphen. 462 | if ((num_leading_hyphens < 1U) || ((num_leading_hyphens > 2U) && !strict)) 463 | isValidDate = NO; 464 | else { 465 | day = segment; 466 | year = nowComponents.year; 467 | dateSpecification = dateOnly; 468 | if (strict && (day > (365U + is_leap_year(year)))) 469 | isValidDate = NO; 470 | } 471 | break; 472 | 473 | default: 474 | isValidDate = NO; 475 | } 476 | } 477 | 478 | if (isValidDate) { 479 | if (isspace(*ch) || (*ch == 'T')) ++ch; 480 | 481 | if (isdigit(*ch)) { 482 | hour = read_segment_2digits(ch, &ch); 483 | if (*ch == timeSep) { 484 | ++ch; 485 | if ((timeSep == ',') || (timeSep == '.')) { 486 | //We can't do fractional minutes when '.' is the segment separator. 487 | //Only allow whole minutes and whole seconds. 488 | minute = read_segment_2digits(ch, &ch); 489 | if (*ch == timeSep) { 490 | ++ch; 491 | second = read_segment_2digits(ch, &ch); 492 | } 493 | } else { 494 | //Allow a fractional minute. 495 | //If we don't get a fraction, look for a seconds segment. 496 | //Otherwise, the fraction of a minute is the seconds. 497 | minute = read_double(ch, &ch); 498 | second = modf(minute, &minute); 499 | if (second > DBL_EPSILON) 500 | second *= 60.0; //Convert fraction (e.g. .5) into seconds (e.g. 30). 501 | else if (*ch == timeSep) { 502 | ++ch; 503 | second = read_double(ch, &ch); 504 | } 505 | } 506 | } 507 | 508 | if (!strict) { 509 | if (isspace(*ch)) ++ch; 510 | } 511 | 512 | switch(*ch) { 513 | case 'Z': 514 | timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; 515 | break; 516 | 517 | case '+': 518 | case '-':; 519 | BOOL negative = (*ch == '-'); 520 | if (isdigit(*++ch)) { 521 | //Read hour offset. 522 | segment = *ch - '0'; 523 | if (isdigit(*++ch)) { 524 | segment *= 10U; 525 | segment += *(ch++) - '0'; 526 | } 527 | tz_hour = (NSInteger)segment; 528 | if (negative) tz_hour = -tz_hour; 529 | 530 | //Optional separator. 531 | if (*ch == timeSep) ++ch; 532 | 533 | if (isdigit(*ch)) { 534 | //Read minute offset. 535 | segment = *ch - '0'; 536 | if (isdigit(*++ch)) { 537 | segment *= 10U; 538 | segment += *ch - '0'; 539 | } 540 | tz_minute = segment; 541 | if (negative) tz_minute = -tz_minute; 542 | } 543 | 544 | NSTimeInterval timeZoneOffset = (tz_hour * 3600) + (tz_minute * 60); 545 | NSNumber *offsetNum = [NSNumber numberWithDouble:timeZoneOffset]; 546 | timeZone = [timeZonesByOffset objectForKey:offsetNum]; 547 | if (!timeZone) { 548 | timeZone = [NSTimeZone timeZoneForSecondsFromGMT:timeZoneOffset]; 549 | if (timeZone) 550 | [timeZonesByOffset setObject:timeZone forKey:offsetNum]; 551 | } 552 | } 553 | } 554 | } 555 | } 556 | 557 | if (isValidDate) { 558 | components.year = year; 559 | components.day = day; 560 | components.hour = hour; 561 | components.minute = (NSInteger)minute; 562 | components.second = (NSInteger)second; 563 | 564 | switch(dateSpecification) { 565 | case monthAndDate: 566 | components.month = month_or_week; 567 | break; 568 | 569 | case week:; 570 | //Adapted from . 571 | //This works by converting the week date into an ordinal date, then letting the next case handle it. 572 | NSUInteger prevYear = year - 1U; 573 | NSUInteger YY = prevYear % 100U; 574 | NSUInteger C = prevYear - YY; 575 | NSUInteger G = YY + YY / 4U; 576 | NSUInteger isLeapYear = (((C / 100U) % 4U) * 5U); 577 | NSUInteger Jan1Weekday = (isLeapYear + G) % 7U; 578 | enum { monday, tuesday, wednesday, thursday/*, friday, saturday, sunday*/ }; 579 | components.day = ((8U - Jan1Weekday) + (7U * (Jan1Weekday > thursday))) + (day - 1U) + (7U * (month_or_week - 2)); 580 | 581 | case dateOnly: //An "ordinal date". 582 | break; 583 | } 584 | } 585 | } //if (!(strict && isdigit(ch[0]))) 586 | 587 | if (outRange) { 588 | if (isValidDate) 589 | range.length = ch - start_of_date; 590 | else 591 | range.location = NSNotFound; 592 | 593 | *outRange = range; 594 | } 595 | if (outTimeZone) { 596 | *outTimeZone = timeZone; 597 | } 598 | 599 | return components; 600 | } 601 | 602 | - (NSDate *) dateFromString:(NSString *)string { 603 | return [self dateFromString:string timeZone:NULL]; 604 | } 605 | - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone { 606 | return [self dateFromString:string timeZone:outTimeZone range:NULL]; 607 | } 608 | - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange { 609 | NSTimeZone *timeZone = nil; 610 | NSDateComponents *components = [self dateComponentsFromString:string timeZone:&timeZone range:outRange]; 611 | if (outTimeZone) 612 | *outTimeZone = timeZone; 613 | parsingCalendar.timeZone = timeZone; 614 | 615 | return [parsingCalendar dateFromComponents:components]; 616 | } 617 | 618 | - (BOOL)getObjectValue:(id *)outValue forString:(NSString *)string errorDescription:(NSString **)error { 619 | NSDate *date = [self dateFromString:string]; 620 | if (outValue) 621 | *outValue = date; 622 | return (date != nil); 623 | } 624 | 625 | #pragma mark Unparsing 626 | 627 | @synthesize format; 628 | @synthesize includeTime; 629 | @synthesize timeSeparator; 630 | 631 | - (NSString *) replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep { 632 | if (timeSep != ':') { 633 | NSMutableString *timeFormatMutable = [timeFormat mutableCopy]; 634 | [timeFormatMutable replaceOccurrencesOfString:@":" 635 | withString:[NSString stringWithCharacters:&timeSep length:1U] 636 | options:NSBackwardsSearch | NSLiteralSearch 637 | range:(NSRange){ 0UL, [timeFormat length] }]; 638 | timeFormat = timeFormatMutable; 639 | } 640 | return timeFormat; 641 | } 642 | 643 | - (NSString *) stringFromDate:(NSDate *)date { 644 | NSTimeZone *timeZone = self.defaultTimeZone; 645 | if (!timeZone) timeZone = [NSTimeZone defaultTimeZone]; 646 | return [self stringFromDate:date timeZone:timeZone]; 647 | } 648 | 649 | - (NSString *) stringFromDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone { 650 | switch (self.format) { 651 | case ISO8601DateFormatCalendar: 652 | return [self stringFromDate:date formatString:ISO_CALENDAR_DATE_FORMAT timeZone:timeZone]; 653 | case ISO8601DateFormatWeek: 654 | return [self weekDateStringForDate:date timeZone:timeZone]; 655 | case ISO8601DateFormatOrdinal: 656 | return [self stringFromDate:date formatString:ISO_ORDINAL_DATE_FORMAT timeZone:timeZone]; 657 | default: 658 | [NSException raise:NSInternalInconsistencyException format:@"self.format was %d, not calendar (%d), week (%d), or ordinal (%d)", self.format, ISO8601DateFormatCalendar, ISO8601DateFormatWeek, ISO8601DateFormatOrdinal]; 659 | return nil; 660 | } 661 | } 662 | 663 | - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat timeZone:(NSTimeZone *)timeZone { 664 | if (includeTime) 665 | dateFormat = [dateFormat stringByAppendingFormat:@"'T'%@", [self replaceColonsInString:ISO_TIME_FORMAT withTimeSeparator:self.timeSeparator]]; 666 | 667 | unparsingCalendar.timeZone = timeZone; 668 | 669 | if (dateFormat != lastUsedFormatString) { 670 | unparsingFormatter = nil; 671 | lastUsedFormatString = dateFormat; 672 | } 673 | 674 | if (!unparsingFormatter) { 675 | unparsingFormatter = [[NSDateFormatter alloc] init]; 676 | unparsingFormatter.formatterBehavior = NSDateFormatterBehavior10_4; 677 | unparsingFormatter.dateFormat = dateFormat; 678 | unparsingFormatter.calendar = unparsingCalendar; 679 | } 680 | 681 | NSString *str = [unparsingFormatter stringForObjectValue:date]; 682 | 683 | if (includeTime) { 684 | NSInteger offset = [timeZone secondsFromGMT]; 685 | offset /= 60; //bring down to minutes 686 | if (offset == 0) 687 | str = [str stringByAppendingString:ISO_TIMEZONE_UTC_FORMAT]; 688 | else 689 | str = [str stringByAppendingFormat:ISO_TIMEZONE_OFFSET_FORMAT, offset / 60, offset % 60]; 690 | } 691 | 692 | //Undo the change we made earlier 693 | unparsingCalendar.timeZone = self.defaultTimeZone; 694 | 695 | return str; 696 | } 697 | 698 | - (NSString *) stringForObjectValue:(id)value { 699 | NSParameterAssert([value isKindOfClass:[NSDate class]]); 700 | 701 | return [self stringFromDate:(NSDate *)value]; 702 | } 703 | 704 | /*Adapted from: 705 | * Algorithm for Converting Gregorian Dates to ISO 8601 Week Date 706 | * Rick McCarty, 1999 707 | * http://personal.ecu.edu/mccartyr/ISOwdALG.txt 708 | */ 709 | - (NSString *) weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone { 710 | unparsingCalendar.timeZone = timeZone; 711 | NSDateComponents *components = [unparsingCalendar components:NSYearCalendarUnit | NSWeekdayCalendarUnit | NSDayCalendarUnit fromDate:date]; 712 | 713 | //Determine the ordinal date. 714 | NSDateComponents *startOfYearComponents = [unparsingCalendar components:NSYearCalendarUnit fromDate:date]; 715 | startOfYearComponents.month = 1; 716 | startOfYearComponents.day = 1; 717 | NSDateComponents *ordinalComponents = [unparsingCalendar components:NSDayCalendarUnit fromDate:[unparsingCalendar dateFromComponents:startOfYearComponents] toDate:date options:0]; 718 | ordinalComponents.day += 1; 719 | 720 | enum { 721 | monday, tuesday, wednesday, thursday, friday, saturday, sunday 722 | }; 723 | enum { 724 | january = 1, february, march, 725 | april, may, june, 726 | july, august, september, 727 | october, november, december 728 | }; 729 | 730 | NSInteger year = components.year; 731 | NSInteger week = 0; 732 | //The old unparser added 6 to [calendarDate dayOfWeek], which was zero-based; components.weekday is one-based, so we now add only 5. 733 | NSInteger dayOfWeek = (components.weekday + 5) % 7; 734 | NSInteger dayOfYear = ordinalComponents.day; 735 | 736 | NSInteger prevYear = year - 1; 737 | 738 | BOOL yearIsLeapYear = is_leap_year(year); 739 | BOOL prevYearIsLeapYear = is_leap_year(prevYear); 740 | 741 | NSInteger YY = prevYear % 100; 742 | NSInteger C = prevYear - YY; 743 | NSInteger G = YY + YY / 4; 744 | NSInteger Jan1Weekday = (((((C / 100) % 4) * 5) + G) % 7); 745 | 746 | NSInteger weekday = ((dayOfYear + Jan1Weekday) - 1) % 7; 747 | 748 | if((dayOfYear <= (7 - Jan1Weekday)) && (Jan1Weekday > thursday)) { 749 | week = 52 + ((Jan1Weekday == friday) || ((Jan1Weekday == saturday) && prevYearIsLeapYear)); 750 | --year; 751 | } else { 752 | NSInteger lengthOfYear = 365 + yearIsLeapYear; 753 | if((lengthOfYear - dayOfYear) < (thursday - weekday)) { 754 | ++year; 755 | week = 1; 756 | } else { 757 | NSInteger J = dayOfYear + (sunday - weekday) + Jan1Weekday; 758 | week = J / 7 - (Jan1Weekday > thursday); 759 | } 760 | } 761 | 762 | NSString *timeString; 763 | if(includeTime) { 764 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 765 | unichar timeSep = self.timeSeparator; 766 | if (!timeSep) timeSep = ISO8601DefaultTimeSeparatorCharacter; 767 | formatter.dateFormat = [self replaceColonsInString:ISO_TIME_WITH_TIMEZONE_FORMAT withTimeSeparator:timeSep]; 768 | 769 | timeString = [formatter stringForObjectValue:date]; 770 | } else 771 | timeString = @""; 772 | 773 | return [NSString stringWithFormat:@"%lu-W%02lu-%02lu%@", (unsigned long)year, (unsigned long)week, ((unsigned long)dayOfWeek) + 1U, timeString]; 774 | } 775 | 776 | @end 777 | 778 | static NSUInteger read_segment(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits) { 779 | NSUInteger num_digits = 0U; 780 | NSUInteger value = 0U; 781 | 782 | while(isdigit(*str)) { 783 | value *= 10U; 784 | value += *str - '0'; 785 | ++num_digits; 786 | ++str; 787 | } 788 | 789 | if (next) *next = str; 790 | if (out_num_digits) *out_num_digits = num_digits; 791 | 792 | return value; 793 | } 794 | static NSUInteger read_segment_4digits(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits) { 795 | NSUInteger num_digits = 0U; 796 | NSUInteger value = 0U; 797 | 798 | if (isdigit(*str)) { 799 | value += *(str++) - '0'; 800 | ++num_digits; 801 | } 802 | 803 | if (isdigit(*str)) { 804 | value *= 10U; 805 | value += *(str++) - '0'; 806 | ++num_digits; 807 | } 808 | 809 | if (isdigit(*str)) { 810 | value *= 10U; 811 | value += *(str++) - '0'; 812 | ++num_digits; 813 | } 814 | 815 | if (isdigit(*str)) { 816 | value *= 10U; 817 | value += *(str++) - '0'; 818 | ++num_digits; 819 | } 820 | 821 | if (next) *next = str; 822 | if (out_num_digits) *out_num_digits = num_digits; 823 | 824 | return value; 825 | } 826 | static NSUInteger read_segment_2digits(const unsigned char *str, const unsigned char **next) { 827 | NSUInteger value = 0U; 828 | 829 | if (isdigit(*str)) 830 | value += *str - '0'; 831 | 832 | if (isdigit(*++str)) { 833 | value *= 10U; 834 | value += *(str++) - '0'; 835 | } 836 | 837 | if (next) *next = str; 838 | 839 | return value; 840 | } 841 | 842 | //strtod doesn't support ',' as a separator. This does. 843 | static double read_double(const unsigned char *str, const unsigned char **next) { 844 | double value = 0.0; 845 | 846 | if (str) { 847 | NSUInteger int_value = 0; 848 | 849 | while(isdigit(*str)) { 850 | int_value *= 10U; 851 | int_value += (*(str++) - '0'); 852 | } 853 | value = int_value; 854 | 855 | if (((*str == ',') || (*str == '.'))) { 856 | ++str; 857 | 858 | register double multiplier, multiplier_multiplier; 859 | multiplier = multiplier_multiplier = 0.1; 860 | 861 | while(isdigit(*str)) { 862 | value += (*(str++) - '0') * multiplier; 863 | multiplier *= multiplier_multiplier; 864 | } 865 | } 866 | } 867 | 868 | if (next) *next = str; 869 | 870 | return value; 871 | } 872 | 873 | static BOOL is_leap_year(NSUInteger year) { 874 | return \ 875 | ((year % 4U) == 0U) 876 | && (((year % 100U) != 0U) 877 | || ((year % 400U) == 0U)); 878 | } 879 | -------------------------------------------------------------------------------- /Sources/ISO8601/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2006 Peter Hosey 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 7 | Neither the name of Peter Hosey nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /Sources/RFC1123/NSDateRFC1123.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDateRFC1123.h 3 | // Filmfest 4 | // 5 | // Created by Marcus Rohrmoser on 19.08.09. 6 | // Copyright 2009 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** Category on NSDate to add rfc1123 dates. Donated from the Filmfest App for free use as in free beer. 12 | http://blog.mro.name/2009/08/nsdateformatter-http-header/ and 13 | http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 14 | */ 15 | @interface NSDate (NSDateRFC1123) 16 | 17 | /** 18 | Convert a RFC1123 'Full-Date' string (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1) into NSDate. 19 | @param value_ something like either @"Fri, 14 Aug 2009 14:45:31 GMT" or @"Sunday, 06-Nov-94 08:49:37 GMT" or @"Sun Nov 6 08:49:37 1994" 20 | @return nil if not parseable. 21 | */ 22 | +(NSDate*)dateFromRFC1123:(NSString*)value_; 23 | 24 | /** 25 | Convert NSDate into a RFC1123 'Full-Date' string (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1). 26 | @return something like @"Fri, 14 Aug 2009 14:45:31 GMT" 27 | */ 28 | -(NSString*)rfc1123String; 29 | 30 | @end -------------------------------------------------------------------------------- /Sources/RFC1123/NSDateRFC1123.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDateRFC1123.m 3 | // Filmfest 4 | // 5 | // Created by Marcus Rohrmoser on 19.08.09. 6 | // Copyright 2009 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "NSDateRFC1123.h" 10 | 11 | @implementation NSDate (NSDateRFC1123) 12 | 13 | +(NSDate*)dateFromRFC1123:(NSString*)value_ 14 | { 15 | if(value_ == nil) 16 | return nil; 17 | static NSDateFormatter *rfc1123 = nil; 18 | if(rfc1123 == nil) 19 | { 20 | rfc1123 = [[NSDateFormatter alloc] init]; 21 | rfc1123.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; 22 | rfc1123.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; 23 | rfc1123.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss z"; 24 | } 25 | NSDate *ret = [rfc1123 dateFromString:value_]; 26 | if(ret != nil) 27 | return ret; 28 | 29 | static NSDateFormatter *rfc850 = nil; 30 | if(rfc850 == nil) 31 | { 32 | rfc850 = [[NSDateFormatter alloc] init]; 33 | rfc850.locale = rfc1123.locale; 34 | rfc850.timeZone = rfc1123.timeZone; 35 | rfc850.dateFormat = @"EEEE',' dd'-'MMM'-'yy HH':'mm':'ss z"; 36 | } 37 | ret = [rfc850 dateFromString:value_]; 38 | if(ret != nil) 39 | return ret; 40 | 41 | static NSDateFormatter *asctime = nil; 42 | if(asctime == nil) 43 | { 44 | asctime = [[NSDateFormatter alloc] init]; 45 | asctime.locale = rfc1123.locale; 46 | asctime.timeZone = rfc1123.timeZone; 47 | asctime.dateFormat = @"EEE MMM d HH':'mm':'ss yyyy"; 48 | } 49 | return [asctime dateFromString:value_]; 50 | } 51 | 52 | 53 | -(NSString*)rfc1123String 54 | { 55 | static NSDateFormatter *df = nil; 56 | if(df == nil) 57 | { 58 | df = [[NSDateFormatter alloc] init]; 59 | df.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; 60 | df.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; 61 | df.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'"; 62 | } 63 | return [df stringFromDate:self]; 64 | } 65 | 66 | 67 | #if 0 68 | // Fri, 14 Aug 2009 14:45:31 GMT 69 | NSLogD(@"Last-Modified: %@", [vc.response.allHeaderFields objectForKey:@"Last-Modified"]); 70 | // df.calendar = @"gregorian"; 71 | NSLogD(@"Now: %@", [NSDate date]); 72 | for(NSString* fmt in [NSArray arrayWithObjects:@"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j", @"k", @"l", @"m", @"n", @"o", @"p", @"q", @"r", @"s", @"t", @"u", @"v", @"w", @"x", @"y", @"z", nil]) 73 | { 74 | rfc1123.dateFormat = [NSString stringWithFormat:@"%@%@%@", fmt, fmt, fmt]; 75 | rfc1123.dateFormat = fmt; 76 | NSLogD(@"Now (%@): %@", rfc1123.dateFormat, [rfc1123 stringFromDate:[NSDate date]]); 77 | rfc1123.dateFormat = [rfc1123.dateFormat uppercaseString]; 78 | NSLogD(@"Now (%@): %@", rfc1123.dateFormat, [rfc1123 stringFromDate:[NSDate date]]); 79 | } 80 | #endif 81 | 82 | @end -------------------------------------------------------------------------------- /Sources/Tests/AMkColTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // AMkColTest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVTest.h" 9 | 10 | @interface AMkColTest : DAVTest { 11 | 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Tests/AMkColTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // AMkColTest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "AMkColTest.h" 9 | 10 | @implementation AMkColTest 11 | 12 | - (void)testRequest { 13 | DAVMakeCollectionRequest *req = [[DAVMakeCollectionRequest alloc] initWithPath:@"davkittest"]; 14 | req.delegate = self; 15 | 16 | STAssertNotNil(req, @"Couldn't create the request"); 17 | 18 | [self.session enqueueRequest:req]; 19 | [req release]; 20 | 21 | [self waitUntilWeAreDone]; 22 | } 23 | 24 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result { 25 | STAssertNil(result, @"No result expected for MKCOL"); 26 | 27 | [self notifyDone]; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Sources/Tests/BPutTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // BPutTest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVTest.h" 9 | 10 | @interface BPutTest : DAVTest { 11 | 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Tests/BPutTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // BPutTest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "BPutTest.h" 9 | 10 | @implementation BPutTest 11 | 12 | - (void)testRequest { 13 | const char *bytes = "blah\0"; 14 | 15 | DAVPutRequest *req = [[DAVPutRequest alloc] initWithPath:@"davkittest/filetest22.txt"]; 16 | req.data = [NSData dataWithBytes:bytes length:strlen(bytes)]; 17 | req.delegate = self; 18 | 19 | STAssertNotNil(req, @"Couldn't create the request"); 20 | 21 | [self.session enqueueRequest:req]; 22 | [req release]; 23 | 24 | [self waitUntilWeAreDone]; 25 | } 26 | 27 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result { 28 | STAssertNil(result, @"No result expected for PUT"); 29 | 30 | [self notifyDone]; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Sources/Tests/CGetTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // CGetTest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVTest.h" 9 | 10 | @interface CGetTest : DAVTest { 11 | 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Tests/CGetTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CGetTest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "CGetTest.h" 9 | 10 | @implementation CGetTest 11 | 12 | - (void)testRequest { 13 | DAVGetRequest *req = [[DAVGetRequest alloc] initWithPath:@"davkittest/filetest22.txt"]; 14 | req.delegate = self; 15 | 16 | STAssertNotNil(req, @"Couldn't create the request"); 17 | 18 | [self.session enqueueRequest:req]; 19 | [req release]; 20 | 21 | [self waitUntilWeAreDone]; 22 | } 23 | 24 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result { 25 | STAssertTrue([result isKindOfClass:[NSData class]], @"Expecting a NSData object for GET requests"); 26 | STAssertTrue([result length] == 4, @"Invalid length (string should be blah)"); 27 | 28 | [self notifyDone]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Sources/Tests/DAVTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DAVTest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | #import "DAVTestSettings.h" 12 | 13 | @interface DAVTest : SenTestCase < DAVRequestDelegate > { 14 | @private 15 | DAVSession *_session; 16 | BOOL _done; 17 | } 18 | 19 | @property (readonly) DAVSession *session; 20 | 21 | - (void)notifyDone; 22 | - (void)waitUntilWeAreDone; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Sources/Tests/DAVTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // DAVTest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVTest.h" 9 | 10 | @implementation DAVTest 11 | 12 | @synthesize session = _session; 13 | 14 | - (void)setUp { 15 | _done = NO; 16 | 17 | DAVCredentials *credentials = [DAVCredentials credentialsWithUsername:USERNAME 18 | password:PASSWORD]; 19 | 20 | STAssertNotNil(credentials, @"Couldn't create credentials"); 21 | STAssertTrue([USERNAME isEqualToString:credentials.username], @"Couldn't set username"); 22 | STAssertTrue([PASSWORD isEqualToString:credentials.password], @"Couldn't set password"); 23 | 24 | NSURL *host = [NSURL URLWithString:HOST]; 25 | 26 | _session = [[DAVSession alloc] initWithRootURL:host credentials:credentials]; 27 | STAssertNotNil(_session, @"Couldn't create DAV session"); 28 | 29 | _session.maxConcurrentRequests = 1; 30 | } 31 | 32 | - (void)notifyDone { 33 | _done = YES; 34 | } 35 | 36 | - (void)waitUntilWeAreDone { 37 | while (!_done) { 38 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 39 | } 40 | } 41 | 42 | - (void)request:(DAVRequest *)aRequest didFailWithError:(NSError *)error { 43 | STFail(@"We have an error: %@", error); 44 | 45 | [self notifyDone]; 46 | } 47 | 48 | - (void)tearDown { 49 | [_session release]; 50 | _session = nil; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Sources/Tests/DCopyTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCopyTest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVTest.h" 9 | 10 | @interface DCopyTest : DAVTest { 11 | 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Tests/DCopyTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCopyTest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DCopyTest.h" 9 | 10 | @implementation DCopyTest 11 | 12 | - (void)testRequest { 13 | DAVCopyRequest *req = [[DAVCopyRequest alloc] initWithPath:@"davkittest/filetest22.txt"]; 14 | req.destinationPath = @"davkittest/filetest23.txt"; 15 | req.overwrite = YES; 16 | req.delegate = self; 17 | 18 | STAssertNotNil(req, @"Couldn't create the request"); 19 | 20 | [self.session enqueueRequest:req]; 21 | [req release]; 22 | 23 | [self waitUntilWeAreDone]; 24 | } 25 | 26 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result { 27 | STAssertNil(result, @"No result expected for COPY"); 28 | 29 | [self notifyDone]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Sources/Tests/EMoveTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // EMoveTest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVTest.h" 9 | 10 | @interface EMoveTest : DAVTest { 11 | 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Tests/EMoveTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // EMoveTest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "EMoveTest.h" 9 | 10 | @implementation EMoveTest 11 | 12 | - (void)testRequest { 13 | DAVMoveRequest *req = [[DAVMoveRequest alloc] initWithPath:@"davkittest/filetest23.txt"]; 14 | req.destinationPath = @"davkittest/filetest24.txt"; 15 | req.delegate = self; 16 | 17 | STAssertNotNil(req, @"Couldn't create the request"); 18 | 19 | [self.session enqueueRequest:req]; 20 | [req release]; 21 | 22 | [self waitUntilWeAreDone]; 23 | } 24 | 25 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result { 26 | STAssertNil(result, @"No result expected for MOVE"); 27 | 28 | [self notifyDone]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Sources/Tests/FListTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // FListTest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVTest.h" 9 | 10 | @interface FListTest : DAVTest { 11 | 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Tests/FListTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // FListTest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "FListTest.h" 9 | 10 | @implementation FListTest 11 | 12 | - (void)testRequest { 13 | DAVListingRequest *req = [[DAVListingRequest alloc] initWithPath:@"davkittest"]; 14 | req.delegate = self; 15 | 16 | STAssertNotNil(req, @"Couldn't create the request"); 17 | 18 | [self.session enqueueRequest:req]; 19 | [req release]; 20 | 21 | [self waitUntilWeAreDone]; 22 | } 23 | 24 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result { 25 | STAssertTrue([result isKindOfClass:[NSArray class]], @"Expecting a NSArray object for PROPFIND requests"); 26 | STAssertTrue([result count] == 3, @"Array should contain 3 objects"); 27 | 28 | [self notifyDone]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Sources/Tests/GDeleteTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // GDeleteTest.h 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "DAVTest.h" 9 | 10 | @interface GDeleteTest : DAVTest { 11 | 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Sources/Tests/GDeleteTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // BDeleteTest.m 3 | // DAVKit 4 | // 5 | // Copyright Matt Rajca 2010. All rights reserved. 6 | // 7 | 8 | #import "GDeleteTest.h" 9 | 10 | @implementation GDeleteTest 11 | 12 | - (void)testRequest { 13 | DAVDeleteRequest *req = [[DAVDeleteRequest alloc] initWithPath:@"davkittest"]; 14 | req.delegate = self; 15 | 16 | STAssertNotNil(req, @"Couldn't create the request"); 17 | 18 | [self.session enqueueRequest:req]; 19 | [req release]; 20 | 21 | [self waitUntilWeAreDone]; 22 | } 23 | 24 | - (void)request:(DAVRequest *)aRequest didSucceedWithResult:(id)result { 25 | STAssertNil(result, @"No result expected for DELETE"); 26 | 27 | [self notifyDone]; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.MattRajca.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | --------------------------------------------------------------------------------